You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1137 lines
31 KiB
1137 lines
31 KiB
3 years ago
|
/*-
|
||
|
* See the file LICENSE for redistribution information.
|
||
|
*
|
||
|
* Copyright (c) 1999, 2000
|
||
|
* Loic Dachary. All rights reserved.
|
||
|
*
|
||
|
* Overview of the code (by Lachlan Andrew, lha@users.sourceforge.net):
|
||
|
*
|
||
|
* This code compresses pages on-the-fly, either using a built-in algorithm,
|
||
|
* or using the zlib library. The compressed page is stored in pages of
|
||
|
* size CMPR_MULTIPLY(db_io->pagesize) -- a fixed multiple of the true
|
||
|
* page size, db_io->pagesize. If the compressed page requires multiple
|
||
|
* pages, extra pages are allocated at the end of the file, and "chained"
|
||
|
* on to the original page. The chain is specified as an array in the first
|
||
|
* page (not a linked list). If a subsequent write of the page requires
|
||
|
* a shorter chain, the spare pages are recorded as "free" and listed in
|
||
|
* the weak-compression database (with suffix given by DB_CMPR_SUFFIX).
|
||
|
*
|
||
|
* When writing a compressed page, extra memory may need to be allocated if
|
||
|
* chaining occurs. This can cause recursive calls to CDB___memp_alloc(),
|
||
|
* since the latter may write dirty cache pages to satisfy the request.
|
||
|
* There is currently an explicit check for recursive calls, both in
|
||
|
* CDB___memp_alloc() and CDB___memp_cmpr_write(), but a more elegant
|
||
|
* solution would be nice.
|
||
|
*
|
||
|
* There also seems to be an issue with the memory allocation for the chain
|
||
|
* array. The small allocations seem to cause fragmentation in the memory
|
||
|
* pool (seen as very many small clean blocks, which don't go away).
|
||
|
*
|
||
|
*
|
||
|
* TODO:
|
||
|
* Keith Bostic says:
|
||
|
* The only change I'd probably think about is if
|
||
|
* we should merge the call to CDB___memp_pg and CDB___memp_cmpr -- kind
|
||
|
* of a stack of page modification routines, that sits on top of
|
||
|
* CDB___os_io. That's a bigger change, but it's probably cleaner
|
||
|
* in the long-run.
|
||
|
*
|
||
|
* Pending questions:
|
||
|
*
|
||
|
* The CMPR structure contains binary data. Should we store them in network order ?
|
||
|
* How is this related to DB_AM_SWAP ?
|
||
|
*
|
||
|
* The calls to cmpr_open/cmpr_close in memp_pgread/pgwrite are probably not
|
||
|
* at the right place / most logical place in the function. I have troubles
|
||
|
* finding out where to put them. They work, that's not the problem. Just don't
|
||
|
* know if they should be before or after.
|
||
|
*
|
||
|
* When opening weakcmpr DB, the DB_THREAD flag is not available. Should it be
|
||
|
* set if the main DB has this flag set ?
|
||
|
*
|
||
|
* In CDB___memp_cmpr, niop is always multiplied by compression factor for page 0.
|
||
|
* I see no problems with this but it's a bit awkward.
|
||
|
*
|
||
|
* In CDB___memp_cmpr_page, the page built fills some fields of the PAGE structure
|
||
|
* others are set to 0. I'm not 100% sure this is enough. It should only impact
|
||
|
* utilities that read pages by incrementing pgno. Only stat does this an it's
|
||
|
* enough for it. I've not found any other context where these fake pages are
|
||
|
* used.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include "db_config.h"
|
||
|
|
||
|
#ifndef lint
|
||
|
static const char sccsid[] = "@(#)mp_cmpr.c 1.1 (Senga) 01/08/99";
|
||
|
#endif /* not lint */
|
||
|
|
||
|
#ifndef NO_SYSTEM_INCLUDES
|
||
|
#include <sys/types.h>
|
||
|
#include <errno.h>
|
||
|
#include <string.h>
|
||
|
#endif
|
||
|
|
||
|
#include "db_int.h"
|
||
|
#include "db_page.h"
|
||
|
#include "shqueue.h"
|
||
|
#include "db_shash.h"
|
||
|
#include "mp.h"
|
||
|
#include "db_page.h"
|
||
|
#include "common_ext.h"
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
#include "WordMonitor.h"
|
||
|
#endif /* DEBUG */
|
||
|
|
||
|
#if 0
|
||
|
#define DEBUG_CMPR 1
|
||
|
#endif
|
||
|
#if 0
|
||
|
#define DEBUG_CMPR_ALLOC 1
|
||
|
#endif
|
||
|
|
||
|
#ifdef HAVE_LIBZ
|
||
|
#include "zlib.h"
|
||
|
#endif /* HAVE_LIBZ */
|
||
|
static int memp_cmpr_zlib_level = -1;
|
||
|
|
||
|
/*
|
||
|
* Helpers declarations.
|
||
|
*/
|
||
|
static int CDB___memp_cmpr_page __P((DB_MPOOLFILE *, CMPR *, DB_IO *, ssize_t *));
|
||
|
|
||
|
/*
|
||
|
* Maximum chain length
|
||
|
* Cast to signed, as -1 used as a flag, which compares bigger on some systems
|
||
|
*/
|
||
|
#define CMPR_MAX (int)(dbenv->mp_cmpr_info->max_npages)
|
||
|
|
||
|
#define CMPR_MULTIPLY(n) ((n) << (dbenv->mp_cmpr_info->coefficient))
|
||
|
#define CMPR_DIVIDE(n) ((n) >> (dbenv->mp_cmpr_info->coefficient))
|
||
|
|
||
|
#ifdef HAVE_LIBZ
|
||
|
static DB_CMPR_INFO default_cmpr_info = {
|
||
|
CDB___memp_cmpr_deflate,
|
||
|
CDB___memp_cmpr_inflate,
|
||
|
3, /* reduce page size by factor of 1<<3 = 8 */
|
||
|
9, /* allow 9 reduced pages, in case "compression" expands data */
|
||
|
6, /* zlib compression level */
|
||
|
NULL
|
||
|
};
|
||
|
#else /* HAVE_LIBZ */
|
||
|
static DB_CMPR_INFO default_cmpr_info = {
|
||
|
0,
|
||
|
0,
|
||
|
0,
|
||
|
0,
|
||
|
0,
|
||
|
NULL
|
||
|
};
|
||
|
#endif /* HAVE_LIBZ */
|
||
|
|
||
|
/*
|
||
|
* Entry point. Functionaly equivalent to CDB___os_io.
|
||
|
* Compress/uncompress pages before returning them or writing them to disk.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* CDB___memp_cmpr --
|
||
|
* Transparent compression read/write
|
||
|
*
|
||
|
* PUBLIC: int CDB___memp_cmpr __P((DB_MPOOLFILE *, BH *, DB_IO *, int, ssize_t *));
|
||
|
*/
|
||
|
int
|
||
|
CDB___memp_cmpr(dbmfp, bhp, db_io, flag, niop)
|
||
|
DB_MPOOLFILE *dbmfp;
|
||
|
BH *bhp;
|
||
|
DB_IO *db_io;
|
||
|
int flag;
|
||
|
ssize_t *niop;
|
||
|
{
|
||
|
size_t orig_pagesize = db_io->pagesize;
|
||
|
db_pgno_t orig_pgno = db_io->pgno;
|
||
|
size_t orig_bytes = db_io->bytes;
|
||
|
DB_ENV *dbenv = dbmfp->dbmp->dbenv;
|
||
|
DB_CMPR_INFO *cmpr_info = dbenv->mp_cmpr_info;
|
||
|
int ret = 0;
|
||
|
|
||
|
db_io->pagesize = CMPR_DIVIDE(db_io->pagesize);
|
||
|
db_io->bytes = CMPR_DIVIDE(db_io->bytes);
|
||
|
|
||
|
#ifdef HAVE_LIBZ
|
||
|
if(memp_cmpr_zlib_level == -1)
|
||
|
{
|
||
|
memp_cmpr_zlib_level = cmpr_info->zlib_flags;
|
||
|
if(memp_cmpr_zlib_level == -1)
|
||
|
memp_cmpr_zlib_level = Z_DEFAULT_COMPRESSION;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* Page 0 is a special case. It contains the metadata information (at most 512 bytes)
|
||
|
* and must not be compressed because it is read with CDB___os_read and not CDB___os_io.
|
||
|
*/
|
||
|
switch (flag) {
|
||
|
case DB_IO_READ:
|
||
|
if(db_io->pgno == 0) {
|
||
|
ret = CDB___os_io(db_io, DB_IO_READ, niop);
|
||
|
*niop = CMPR_MULTIPLY(*niop);
|
||
|
} else
|
||
|
ret = CDB___memp_cmpr_read(dbmfp, bhp, db_io, niop);
|
||
|
break;
|
||
|
case DB_IO_WRITE:
|
||
|
if(db_io->pgno == 0) {
|
||
|
ret = CDB___os_io(db_io, DB_IO_WRITE, niop);
|
||
|
*niop = CMPR_MULTIPLY(*niop);
|
||
|
} else
|
||
|
ret = CDB___memp_cmpr_write(dbmfp, bhp, db_io, niop);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
db_io->pgno = orig_pgno;
|
||
|
db_io->pagesize = orig_pagesize;
|
||
|
db_io->bytes = orig_bytes;
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CDB___memp_cmpr_read --
|
||
|
* Transparent compression read
|
||
|
*
|
||
|
* PUBLIC: int CDB___memp_cmpr_read __P((DB_MPOOLFILE *, BH *, DB_IO *, ssize_t *));
|
||
|
*/
|
||
|
int
|
||
|
CDB___memp_cmpr_read(dbmfp, bhp, db_io, niop)
|
||
|
DB_MPOOLFILE *dbmfp;
|
||
|
BH *bhp;
|
||
|
DB_IO *db_io;
|
||
|
ssize_t *niop;
|
||
|
{
|
||
|
CMPR cmpr;
|
||
|
int ret;
|
||
|
int chain = 0;
|
||
|
u_int8_t *buffcmpr = 0;
|
||
|
int buffcmpr_length = 0;
|
||
|
int chain_length = 0;
|
||
|
db_pgno_t first_pgno = db_io->pgno;
|
||
|
DB_ENV *dbenv = dbmfp->dbmp->dbenv;
|
||
|
DB_CMPR_INFO *cmpr_info = dbenv->mp_cmpr_info;
|
||
|
/*
|
||
|
* By default the compression does not use too much space,
|
||
|
* hence the chain is empty.
|
||
|
*/
|
||
|
F_CLR(bhp, BH_CMPR);
|
||
|
|
||
|
/*
|
||
|
* Read first page (if no overflow, this is the only one)
|
||
|
*/
|
||
|
ret = CDB___os_io(db_io, DB_IO_READ, niop);
|
||
|
|
||
|
/*
|
||
|
* An error or partial read on the first page means that we're not
|
||
|
* going anywhere.
|
||
|
*/
|
||
|
if(ret || *niop < db_io->pagesize)
|
||
|
goto err;
|
||
|
|
||
|
/*
|
||
|
* Read the cmpr header from page.
|
||
|
*/
|
||
|
memcpy(&cmpr, db_io->buf, sizeof(CMPR));
|
||
|
|
||
|
/*
|
||
|
* If not at the beginning of compressed page chain, build
|
||
|
* a fake page.
|
||
|
*/
|
||
|
if(F_ISSET(&cmpr, DB_CMPR_FREE) || F_ISSET(&cmpr, DB_CMPR_INTERNAL)) {
|
||
|
ret = CDB___memp_cmpr_page(dbmfp, &cmpr, db_io, niop);
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Sanity check. Happens if file corrupted.
|
||
|
*/
|
||
|
if(!F_ISSET(&cmpr, DB_CMPR_FIRST)) {
|
||
|
CDB___db_err(dbmfp->dbmp->dbenv, "CDB___memp_cmpr_read: expected DB_CMPR_FIRST flag set at pgno = %ld", db_io->pgno);
|
||
|
ret = CDB___db_panic(dbmfp->dbmp->dbenv, EINVAL);
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
if((ret = CDB___os_malloc(db_io->pagesize * CMPR_MAX, NULL, &buffcmpr)) != 0)
|
||
|
goto err;
|
||
|
|
||
|
do {
|
||
|
/*
|
||
|
* Read the first part of the compressed data from page.
|
||
|
*/
|
||
|
memcpy(buffcmpr + buffcmpr_length, DB_CMPR_DATA(db_io), DB_CMPR_PAGESIZE(db_io));
|
||
|
buffcmpr_length += DB_CMPR_PAGESIZE(db_io);
|
||
|
|
||
|
/*
|
||
|
* Flag must only contain FIRST|INTERNAL and/or CHAIN. If other bits are
|
||
|
* set, the data is corrupted. Removing the FIRST|INTERNAL bits and checking
|
||
|
* the CHAIN bit with == instead of F_ISSET verify this.
|
||
|
*/
|
||
|
F_CLR(&cmpr, DB_CMPR_FIRST | DB_CMPR_INTERNAL);
|
||
|
chain = cmpr.flags;
|
||
|
|
||
|
if(chain == DB_CMPR_CHAIN) {
|
||
|
/*
|
||
|
* Overflow Case. Continue reading data from extra pages.
|
||
|
*/
|
||
|
|
||
|
chain_length++;
|
||
|
if(chain_length >= CMPR_MAX) {
|
||
|
CDB___db_err(dbmfp->dbmp->dbenv, "CDB___memp_cmpr_read: compression chain too long at pgno = %ld", db_io->pgno);
|
||
|
ret = CDB___db_panic(dbmfp->dbmp->dbenv, EINVAL);
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
if(cmpr.next == 0) {
|
||
|
CDB___db_err(dbmfp->dbmp->dbenv, "CDB___memp_cmpr_read: cmpr.next is null at pgno = %ld", chain, db_io->pgno);
|
||
|
ret = CDB___db_panic(dbmfp->dbmp->dbenv, EINVAL);
|
||
|
goto err;
|
||
|
}
|
||
|
/*
|
||
|
* Keep the chain in buffer header.
|
||
|
* Freed when bhp freed in CDB___memp_bhfree().
|
||
|
*/
|
||
|
CDB___memp_cmpr_alloc_chain(dbmfp->dbmp, bhp, BH_CMPR_POOL);
|
||
|
|
||
|
bhp->chain[chain_length - 1] = cmpr.next;
|
||
|
db_io->pgno = cmpr.next;
|
||
|
/*
|
||
|
* Read data from extra page.
|
||
|
*/
|
||
|
if((ret = CDB___os_io(db_io, DB_IO_READ, niop)) != 0 ||
|
||
|
*niop != db_io->pagesize) {
|
||
|
ret = EIO;
|
||
|
goto err;
|
||
|
}
|
||
|
/*
|
||
|
* Read the cmpr header from this extra page
|
||
|
*/
|
||
|
memcpy(&cmpr, db_io->buf, sizeof(CMPR));
|
||
|
} else if(chain != 0) {
|
||
|
CDB___db_err(dbmfp->dbmp->dbenv, "CDB___memp_cmpr_read: unexpected compression flag value 0x%x at pgno = %ld", chain, db_io->pgno);
|
||
|
ret = CDB___db_panic(dbmfp->dbmp->dbenv, ret);
|
||
|
goto err;
|
||
|
} else if(cmpr.next != 0) {
|
||
|
CDB___db_err(dbmfp->dbmp->dbenv, "CDB___memp_cmpr_read: cmpr.next is not null at pgno = %ld", chain, db_io->pgno);
|
||
|
ret = CDB___db_panic(dbmfp->dbmp->dbenv, ret);
|
||
|
goto err;
|
||
|
}
|
||
|
} while(chain);
|
||
|
|
||
|
/*
|
||
|
* We gathered all the compressed data in buffcmpr, inflate it.
|
||
|
*/
|
||
|
|
||
|
if(cmpr_info->zlib_flags != 0)
|
||
|
ret = CDB___memp_cmpr_inflate(buffcmpr, buffcmpr_length, db_io->buf, CMPR_MULTIPLY(db_io->pagesize), cmpr_info->user_data);
|
||
|
else
|
||
|
ret = (*cmpr_info->uncompress)(buffcmpr, buffcmpr_length, db_io->buf, CMPR_MULTIPLY(db_io->pagesize), cmpr_info->user_data);
|
||
|
|
||
|
if(ret != 0)
|
||
|
{
|
||
|
CDB___db_err(dbmfp->dbmp->dbenv, "CDB___memp_cmpr_read: unable to uncompress page at pgno = %ld", first_pgno);
|
||
|
ret = CDB___db_panic(dbmfp->dbmp->dbenv, ret);
|
||
|
goto err;
|
||
|
}
|
||
|
#ifdef DEBUG
|
||
|
{
|
||
|
int ratio = buffcmpr_length > 0 ? (CMPR_MULTIPLY(db_io->pagesize) / buffcmpr_length) : 0;
|
||
|
if(ratio > 10) ratio = 10;
|
||
|
word_monitor_add(WORD_MONITOR_COMPRESS_01 + ratio, 1);
|
||
|
}
|
||
|
#endif /* DEBUG */
|
||
|
|
||
|
*niop = CMPR_MULTIPLY(db_io->pagesize);
|
||
|
|
||
|
err:
|
||
|
#ifdef DEBUG_CMPR
|
||
|
if(chain_length > 0) {
|
||
|
int i;
|
||
|
fprintf(stderr,"CDB___memp_cmpr_read:: chain_length (number of overflow pages):%2d\n",chain_length);
|
||
|
fprintf(stderr,"CDB___memp_cmpr_read:: chain ");
|
||
|
for(i = 0; i < chain_length; i++)
|
||
|
fprintf(stderr, "%d, ", bhp->chain[i]);
|
||
|
fprintf(stderr, "\n");
|
||
|
}
|
||
|
#endif
|
||
|
if(buffcmpr) CDB___os_free(buffcmpr, 0);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CDB___memp_cmpr_write --
|
||
|
* Transparent compression write
|
||
|
*
|
||
|
* PUBLIC: int CDB___memp_cmpr_write __P((DB_MPOOLFILE *, BH *, DB_IO *, ssize_t *));
|
||
|
*/
|
||
|
int
|
||
|
CDB___memp_cmpr_write(dbmfp, bhp, db_io, niop)
|
||
|
DB_MPOOLFILE *dbmfp;
|
||
|
BH *bhp;
|
||
|
DB_IO *db_io;
|
||
|
ssize_t *niop;
|
||
|
{
|
||
|
CMPR cmpr;
|
||
|
int chain_length = 0;
|
||
|
int first_nonreused_chain_pos = 0;
|
||
|
int ret;
|
||
|
u_int8_t *buffcmpr = 0;
|
||
|
u_int8_t *buffp;
|
||
|
unsigned int buffcmpr_length;
|
||
|
u_int8_t *orig_buff = db_io->buf;
|
||
|
DB_ENV *dbenv = dbmfp->dbmp->dbenv;
|
||
|
DB_CMPR_INFO *cmpr_info = dbenv->mp_cmpr_info;
|
||
|
|
||
|
if((ret = CDB___os_malloc(CMPR_MULTIPLY(db_io->bytes), NULL, &db_io->buf)) != 0)
|
||
|
goto err;
|
||
|
|
||
|
|
||
|
if(cmpr_info->zlib_flags != 0)
|
||
|
ret = CDB___memp_cmpr_deflate(orig_buff, CMPR_MULTIPLY(db_io->pagesize), &buffcmpr, &buffcmpr_length, cmpr_info->user_data);
|
||
|
else
|
||
|
ret = (*cmpr_info->compress)(orig_buff, CMPR_MULTIPLY(db_io->pagesize), &buffcmpr, &buffcmpr_length, cmpr_info->user_data);
|
||
|
|
||
|
if(ret != 0)
|
||
|
{
|
||
|
CDB___db_err(dbmfp->dbmp->dbenv, "CDB___memp_cmpr_write: unable to compress page at pgno = %ld", db_io->pgno);
|
||
|
ret = CDB___db_panic(dbmfp->dbmp->dbenv, ret);
|
||
|
goto err;
|
||
|
}
|
||
|
#ifdef DEBUG
|
||
|
{
|
||
|
int ratio = buffcmpr_length > 0 ? (CMPR_MULTIPLY(db_io->pagesize) / buffcmpr_length) : 0;
|
||
|
if(ratio > 10) ratio = 10;
|
||
|
word_monitor_add(WORD_MONITOR_COMPRESS_01 + ratio, 1);
|
||
|
}
|
||
|
#endif /* DEBUG */
|
||
|
|
||
|
/*
|
||
|
* This can never happen.
|
||
|
*/
|
||
|
if(buffcmpr_length > DB_CMPR_PAGESIZE(db_io) * CMPR_MAX) {
|
||
|
CDB___db_err(dbmfp->dbmp->dbenv, "CDB___memp_cmpr_write: compressed data is too big at pgno = %ld", db_io->pgno);
|
||
|
ret = CDB___db_panic(dbmfp->dbmp->dbenv, EINVAL);
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
buffp = buffcmpr;
|
||
|
cmpr.flags = DB_CMPR_FIRST;
|
||
|
cmpr.next = 0;
|
||
|
|
||
|
/* write pages until the whole compressed data is written */
|
||
|
do {
|
||
|
unsigned int length = buffcmpr_length - (buffp - buffcmpr);
|
||
|
unsigned int copy_length = length > DB_CMPR_PAGESIZE(db_io) ? DB_CMPR_PAGESIZE(db_io) : length;
|
||
|
/*
|
||
|
* We handle serious compression stuff only if we need to.
|
||
|
* overflow! the compressed buffer is too big -> get extra page
|
||
|
*/
|
||
|
if(length > copy_length) {
|
||
|
if (dbmfp->dbmp->recursion_level >= 2 ) {
|
||
|
fprintf(stderr,"CDB___memp_cmpr_write: Wanted %d > %d bytes\n", length, copy_length);
|
||
|
fprintf(stderr,"Reducing wordlist_cache_dirty_level may help.\n");
|
||
|
ret = EBUSY;
|
||
|
goto err;
|
||
|
}
|
||
|
chain_length++;
|
||
|
if(chain_length >= CMPR_MAX) {
|
||
|
CDB___db_err(dbmfp->dbmp->dbenv, "CDB___memp_cmpr_write: chain_length overflow");
|
||
|
ret = CDB___db_panic(dbmfp->dbmp->dbenv, EINVAL);
|
||
|
goto err;
|
||
|
}
|
||
|
F_SET(&cmpr, DB_CMPR_CHAIN);
|
||
|
if((ret = CDB___memp_cmpr_alloc(dbmfp, &cmpr.next, bhp, &first_nonreused_chain_pos)) != 0)
|
||
|
goto err;
|
||
|
CDB___memp_cmpr_alloc_chain(dbmfp->dbmp, bhp, BH_CMPR_OS);
|
||
|
bhp->chain[chain_length - 1] = cmpr.next;
|
||
|
}
|
||
|
/* write in the cmpr header */
|
||
|
memcpy(db_io->buf, &cmpr, DB_CMPR_OVERHEAD);
|
||
|
/* write in what's left of the compressed buffer (and that also fits in) */
|
||
|
memcpy(db_io->buf + DB_CMPR_OVERHEAD, buffp, copy_length);
|
||
|
buffp += copy_length;
|
||
|
/* actual output */
|
||
|
if((ret = CDB___os_io(db_io, DB_IO_WRITE, niop)) != 0 ||
|
||
|
*niop != db_io->pagesize) {
|
||
|
ret = EIO;
|
||
|
goto err;
|
||
|
}
|
||
|
db_io->pgno = cmpr.next;
|
||
|
cmpr.flags = DB_CMPR_INTERNAL;
|
||
|
cmpr.next = 0;
|
||
|
} while((unsigned int)(buffp - buffcmpr) < buffcmpr_length);
|
||
|
|
||
|
#ifdef DEBUG_CMPR
|
||
|
fprintf(stderr,"CDB___memp_cmpr_write:: chain_length (number of overflow pages):%2d\n",chain_length);
|
||
|
if(chain_length > 0) {
|
||
|
int i;
|
||
|
fprintf(stderr,"CDB___memp_cmpr_write:: chain ");
|
||
|
for(i = 0; i < chain_length; i++)
|
||
|
fprintf(stderr, "%d, ", bhp->chain[i]);
|
||
|
fprintf(stderr, "\n");
|
||
|
}
|
||
|
#endif
|
||
|
/*
|
||
|
* If the chain was not completely reused, free the remaining pages (the page compression
|
||
|
* rate is better).
|
||
|
*/
|
||
|
if(F_ISSET(bhp, BH_CMPR) && first_nonreused_chain_pos >= 0) {
|
||
|
int i;
|
||
|
CMPR cmpr;
|
||
|
cmpr.flags = DB_CMPR_FREE;
|
||
|
cmpr.next = 0;
|
||
|
memcpy(db_io->buf, &cmpr, sizeof(CMPR));
|
||
|
for(i = first_nonreused_chain_pos; i < (CMPR_MAX - 1) && bhp->chain[i]; i++) {
|
||
|
if((ret = CDB___memp_cmpr_free(dbmfp, bhp->chain[i])) != 0)
|
||
|
goto err;
|
||
|
/*
|
||
|
* Mark the page as free for recovery.
|
||
|
*/
|
||
|
db_io->pgno = bhp->chain[i];
|
||
|
if((ret = CDB___os_io(db_io, DB_IO_WRITE, niop)) != 0 ||
|
||
|
*niop != db_io->pagesize) {
|
||
|
ret = EIO;
|
||
|
goto err;
|
||
|
}
|
||
|
bhp->chain[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CDB___memp_cmpr_free_chain(dbmfp->dbmp, bhp);
|
||
|
|
||
|
/*
|
||
|
* In case of success, always pretend that we exactly wrote the
|
||
|
* all bytes of the original pagesize.
|
||
|
*/
|
||
|
*niop = CMPR_MULTIPLY(db_io->pagesize);
|
||
|
|
||
|
err:
|
||
|
CDB___os_free(db_io->buf, 0);
|
||
|
db_io->buf = orig_buff;
|
||
|
if(buffcmpr) CDB___os_free(buffcmpr, 0);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Helpers
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* CDB___memp_cmpr_page --
|
||
|
* Build a fake page. This function is a CDB___memp_cmpr_read helper.
|
||
|
*
|
||
|
*/
|
||
|
static int
|
||
|
CDB___memp_cmpr_page(dbmfp, cmpr, db_io, niop)
|
||
|
DB_MPOOLFILE *dbmfp;
|
||
|
CMPR *cmpr;
|
||
|
DB_IO *db_io;
|
||
|
ssize_t *niop;
|
||
|
{
|
||
|
DB_ENV *dbenv = dbmfp->dbmp->dbenv;
|
||
|
int ret = 0;
|
||
|
PAGE page;
|
||
|
|
||
|
memset((char*)&page, '\0', sizeof(PAGE));
|
||
|
|
||
|
page.pgno = db_io->pgno;
|
||
|
page.type = F_ISSET(cmpr, DB_CMPR_FREE) ? P_CMPR_FREE : P_CMPR_INTERNAL;
|
||
|
|
||
|
/*
|
||
|
* Sanity check
|
||
|
*/
|
||
|
if(db_io->pagesize < sizeof(PAGE)) {
|
||
|
ret = ENOMEM;
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
memcpy(db_io->buf, (char*)&page, sizeof(PAGE));
|
||
|
|
||
|
*niop = CMPR_MULTIPLY(db_io->pagesize);
|
||
|
|
||
|
err:
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CDB___memp_cmpr_inflate --
|
||
|
* Decompress buffer
|
||
|
*
|
||
|
* PUBLIC: int CDB___memp_cmpr_inflate __P((const u_int8_t *, int, u_int8_t *, int, void *));
|
||
|
*/
|
||
|
int
|
||
|
CDB___memp_cmpr_inflate(inbuff, inbuff_length, outbuff, outbuff_length, user_data)
|
||
|
const u_int8_t* inbuff;
|
||
|
int inbuff_length;
|
||
|
u_int8_t* outbuff;
|
||
|
int outbuff_length;
|
||
|
void *user_data;
|
||
|
{
|
||
|
#ifdef HAVE_LIBZ
|
||
|
int ret = 0;
|
||
|
z_stream c_stream;
|
||
|
|
||
|
c_stream.zalloc=(alloc_func)0;
|
||
|
c_stream.zfree=(free_func)0;
|
||
|
c_stream.opaque=(voidpf)0;
|
||
|
c_stream.next_in = (Bytef*)inbuff;
|
||
|
c_stream.avail_in = inbuff_length;
|
||
|
c_stream.next_out = outbuff;
|
||
|
c_stream.avail_out = outbuff_length;
|
||
|
|
||
|
if(inflateInit(&c_stream) != Z_OK ||
|
||
|
inflate(&c_stream, Z_FINISH) != Z_STREAM_END ||
|
||
|
inflateEnd(&c_stream) != Z_OK)
|
||
|
ret = EIO;
|
||
|
|
||
|
/*
|
||
|
* The uncompressed data must *exactly* fill outbuff_length.
|
||
|
*/
|
||
|
if(c_stream.avail_out != 0)
|
||
|
ret = EIO;
|
||
|
|
||
|
return ret;
|
||
|
#else /* HAVE_LIBZ */
|
||
|
return EINVAL;
|
||
|
#endif /* HAVE_LIBZ */
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* CDB___memp_cmpr_deflate --
|
||
|
* Compress buffer
|
||
|
*
|
||
|
* PUBLIC: int CDB___memp_cmpr_deflate __P((const u_int8_t *, int, u_int8_t **, int*, void *));
|
||
|
*/
|
||
|
int
|
||
|
CDB___memp_cmpr_deflate(inbuff, inbuff_length, outbuffp, outbuff_lengthp, user_data)
|
||
|
const u_int8_t* inbuff;
|
||
|
int inbuff_length;
|
||
|
u_int8_t** outbuffp;
|
||
|
int* outbuff_lengthp;
|
||
|
void *user_data;
|
||
|
{
|
||
|
#ifdef HAVE_LIBZ
|
||
|
int ret = 0;
|
||
|
int r;
|
||
|
int off = 0;
|
||
|
int freesp = 0;
|
||
|
z_stream c_stream;
|
||
|
u_int8_t* outbuff;
|
||
|
|
||
|
/*
|
||
|
* Z_FINISH can be used immediately after deflateInit if all the compression
|
||
|
* is to be done in a single step. In this case, avail_out must be at least
|
||
|
* 0.1% larger than avail_in plus 12 bytes. If deflate does not return
|
||
|
* Z_STREAM_END, then it must be called again as described above.
|
||
|
*
|
||
|
* !!!
|
||
|
* In order to avoid division by 1000, divide by 512 (2^9) using shift.
|
||
|
* That is, make the buffer 0.2% larger.
|
||
|
*/
|
||
|
int outbuff_length = inbuff_length + (inbuff_length >> 9) + 12;
|
||
|
|
||
|
*outbuffp = 0;
|
||
|
*outbuff_lengthp = 0;
|
||
|
|
||
|
if(CDB___os_malloc(outbuff_length, NULL, &outbuff) != 0) {
|
||
|
ret = ENOMEM;
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Clear possible garbage in the page
|
||
|
*/
|
||
|
{
|
||
|
PAGE* pg = (PAGE*)inbuff;
|
||
|
switch(TYPE(pg)) {
|
||
|
case P_IBTREE:
|
||
|
case P_LBTREE:
|
||
|
off = LOFFSET(pg);
|
||
|
freesp = P_FREESPACE(pg);
|
||
|
memset((char*)(inbuff + off), 0, freesp);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
c_stream.zalloc=(alloc_func)0;
|
||
|
c_stream.zfree=(free_func)0;
|
||
|
c_stream.opaque=(voidpf)0;
|
||
|
|
||
|
if(deflateInit(&c_stream, memp_cmpr_zlib_level) != Z_OK)
|
||
|
{
|
||
|
ret = EIO;
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
c_stream.next_in = (Bytef*)inbuff;
|
||
|
c_stream.avail_in = inbuff_length;
|
||
|
c_stream.next_out = outbuff;
|
||
|
c_stream.avail_out = outbuff_length;
|
||
|
|
||
|
while((r = deflate(&c_stream, Z_FINISH)) != Z_STREAM_END && r == Z_OK)
|
||
|
;
|
||
|
|
||
|
if(r != Z_STREAM_END)
|
||
|
ret = EIO;
|
||
|
|
||
|
if(deflateEnd(&c_stream) != Z_OK)
|
||
|
ret = EIO;
|
||
|
|
||
|
if(ret == 0) {
|
||
|
*outbuffp = outbuff;
|
||
|
*outbuff_lengthp = outbuff_length - c_stream.avail_out;
|
||
|
} else {
|
||
|
CDB___os_free(outbuff, outbuff_length);
|
||
|
}
|
||
|
#ifdef DEBUG_CMPR
|
||
|
fprintf(stderr,"CDB___memp_cmpr_deflate:: compress %d bytes to %d \n", inbuff_length, *outbuff_lengthp);
|
||
|
#endif
|
||
|
|
||
|
err:
|
||
|
return ret;
|
||
|
#else /* HAVE_LIBZ */
|
||
|
return EINVAL;
|
||
|
#endif /* HAVE_LIBZ */
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* CDB___memp_cmpr_info_valid --
|
||
|
* Compute compressed page size
|
||
|
*/
|
||
|
static int
|
||
|
CDB___memp_cmpr_info_valid(dbenv,cmpr_info)
|
||
|
DB_ENV *dbenv;
|
||
|
DB_CMPR_INFO *cmpr_info;
|
||
|
{
|
||
|
int ret = 0;
|
||
|
if(!cmpr_info ) {
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_info_valid: cmpr_info == NULL");
|
||
|
ret = CDB___db_panic(dbenv, EINVAL);
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
if(!cmpr_info->compress ) {
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_info_valid: compress == NULL!");
|
||
|
ret = CDB___db_panic(dbenv, EINVAL);
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
if(!cmpr_info->uncompress ) {
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_info_valid: uncompress == NULL!");
|
||
|
ret = CDB___db_panic(dbenv, EINVAL);
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
if(cmpr_info->coefficient == 0 || cmpr_info->coefficient > 5 ) {
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_info_valid: coefficient should be > 0 and < 5 coefficient=%d ", cmpr_info->coefficient);
|
||
|
ret = CDB___db_panic(dbenv, EINVAL);
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
if(cmpr_info->max_npages == 0 || cmpr_info->max_npages > 128 ) {
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_info_valid: max_npages should be > 0 and < 128 max_npages=%d ", cmpr_info->max_npages);
|
||
|
ret = CDB___db_panic(dbenv, EINVAL);
|
||
|
goto err;
|
||
|
}
|
||
|
err:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* __memp_cmpr_pagesize --
|
||
|
* Compute compressed page size
|
||
|
*
|
||
|
* PUBLIC: u_int8_t CDB___memp_cmpr_coefficient __P((DB_ENV *dbenv));
|
||
|
*/
|
||
|
u_int8_t
|
||
|
CDB___memp_cmpr_coefficient(dbenv)
|
||
|
DB_ENV *dbenv;
|
||
|
{
|
||
|
u_int8_t ret = 0;
|
||
|
|
||
|
if(!dbenv || !dbenv->mp_cmpr_info) {
|
||
|
ret = default_cmpr_info.coefficient;
|
||
|
} else {
|
||
|
CDB___memp_cmpr_info_valid(dbenv, dbenv->mp_cmpr_info);
|
||
|
ret = dbenv->mp_cmpr_info->coefficient;
|
||
|
}
|
||
|
|
||
|
return (ret);
|
||
|
}
|
||
|
/*
|
||
|
* Initialisation of page compression
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* CDB___memp_cmpr_open --
|
||
|
* Open the db that contains the free compression pages.
|
||
|
*
|
||
|
* PUBLIC: int CDB___memp_cmpr_open __P((const char *, DB_ENV *, CMPR_CONTEXT *));
|
||
|
*/
|
||
|
int
|
||
|
CDB___memp_cmpr_open(dbenv, path, flags, mode, cmpr_context)
|
||
|
DB_ENV *dbenv;
|
||
|
const char *path;
|
||
|
int flags;
|
||
|
int mode;
|
||
|
CMPR_CONTEXT *cmpr_context;
|
||
|
{
|
||
|
int ret;
|
||
|
char* tmp = 0;
|
||
|
int tmp_length = strlen(path) + strlen(DB_CMPR_SUFFIX) + 1;
|
||
|
|
||
|
/*
|
||
|
* Management of pages containing data when the compression does not achieve
|
||
|
* the expected compression ratio.
|
||
|
*/
|
||
|
{
|
||
|
DB *dbp;
|
||
|
if((ret = CDB___os_malloc(tmp_length, NULL, &tmp)) != 0)
|
||
|
goto err;
|
||
|
sprintf(tmp, "%s%s", path, DB_CMPR_SUFFIX);
|
||
|
|
||
|
/* Use *standalone* database, to prevent recursion when writing pages */
|
||
|
/* from the cache, shared with other members of the environment */
|
||
|
if(CDB_db_create(&dbp, NULL, 0) != 0)
|
||
|
goto err;
|
||
|
|
||
|
cmpr_context->weakcmpr = dbp;
|
||
|
|
||
|
(dbp->set_flags)(dbp, DB_RECNUM);
|
||
|
|
||
|
LF_CLR(DB_COMPRESS);
|
||
|
if(!LF_ISSET(DB_RDONLY)) LF_SET(DB_CREATE);
|
||
|
if((ret = (dbp->open)(dbp, tmp, NULL, DB_BTREE, flags, mode)) != 0)
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Initialisation of cmpr_context
|
||
|
*/
|
||
|
if(!dbenv->mp_cmpr_info) {
|
||
|
if(default_cmpr_info.compress == 0) {
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_open: zlib compression not available, re-compile --with-zlib=DIR");
|
||
|
ret = CDB___db_panic(dbenv, EINVAL);
|
||
|
goto err;
|
||
|
}
|
||
|
dbenv->mp_cmpr_info = &default_cmpr_info;
|
||
|
}
|
||
|
/*
|
||
|
* Check if cmpr_info is sane
|
||
|
*/
|
||
|
if((ret = CDB___memp_cmpr_info_valid(dbenv, dbenv->mp_cmpr_info)))
|
||
|
goto err;
|
||
|
|
||
|
err:
|
||
|
if(tmp) CDB___os_free(tmp, tmp_length);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CDB___memp_cmpr_close --
|
||
|
* Close the db that contains the free compression pages.
|
||
|
*
|
||
|
* PUBLIC: int CDB___memp_cmpr_close __P((CMPR_CONTEXT *));
|
||
|
*/
|
||
|
int
|
||
|
CDB___memp_cmpr_close(cmpr_context)
|
||
|
CMPR_CONTEXT *cmpr_context;
|
||
|
{
|
||
|
int ret = 0;
|
||
|
|
||
|
if(cmpr_context->weakcmpr == 0) {
|
||
|
ret = EINVAL;
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
if((ret = cmpr_context->weakcmpr->close(cmpr_context->weakcmpr, 0)) != 0)
|
||
|
goto err;
|
||
|
cmpr_context->weakcmpr = 0;
|
||
|
|
||
|
err:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CDB___memp_cmpr_alloc --
|
||
|
* Get a new free page to store weak compression data.
|
||
|
*
|
||
|
* PUBLIC: int CDB___memp_cmpr_alloc __P((DB_MPOOLFILE *, db_pgno_t *, BH *, int *));
|
||
|
*/
|
||
|
int
|
||
|
CDB___memp_cmpr_alloc(dbmfp, pgnop, bhp, first_nonreused_chain_posp)
|
||
|
DB_MPOOLFILE *dbmfp;
|
||
|
db_pgno_t *pgnop;
|
||
|
BH *bhp;
|
||
|
int *first_nonreused_chain_posp;
|
||
|
{
|
||
|
DB_ENV *dbenv = dbmfp->dbmp->dbenv;
|
||
|
int ret = 0;
|
||
|
|
||
|
#ifdef DEBUG_CMPR
|
||
|
fprintf(stderr,"CDB___memp_cmpr_alloc:: bhp:%8x bhp->chain:%8x first_nonreused_chain_posp:%2d\n", bhp, bhp->chain, *first_nonreused_chain_posp);
|
||
|
#endif
|
||
|
if(F_ISSET(bhp, BH_CMPR) && bhp->chain == NULL) {
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_alloc: BH_CMPR set and bhp->chain == NULL");
|
||
|
ret = CDB___db_panic(dbenv, EINVAL);
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
if((*first_nonreused_chain_posp) >= (CMPR_MAX - 1)) {
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_alloc: first_nonreused_chain_pos >= (CMPR_MAX - 1)");
|
||
|
ret = CDB___db_panic(dbenv, EINVAL);
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If possible reuse an existing chain.
|
||
|
*/
|
||
|
if((*first_nonreused_chain_posp) >= 0 && F_ISSET(bhp, BH_CMPR) && bhp->chain[*first_nonreused_chain_posp]) {
|
||
|
*pgnop = bhp->chain[*first_nonreused_chain_posp];
|
||
|
(*first_nonreused_chain_posp)++;
|
||
|
#ifdef DEBUG_CMPR
|
||
|
fprintf(stderr,"CDB___memp_cmpr_alloc:: reusing page in chain \n");
|
||
|
#endif
|
||
|
} else {
|
||
|
DB *db = dbmfp->cmpr_context.weakcmpr;
|
||
|
DBT key;
|
||
|
DBT data;
|
||
|
db_recno_t recno = 1;
|
||
|
|
||
|
/* all pages in bhp->chain are now reused */
|
||
|
(*first_nonreused_chain_posp) = -1;
|
||
|
#ifdef DEBUG_CMPR
|
||
|
fprintf(stderr,"CDB___memp_cmpr_alloc:: no more reusable pages in chain\n");
|
||
|
#endif
|
||
|
|
||
|
if(db == 0) {
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_alloc: dbmfp->cmpr_context.weakcmpr is null");
|
||
|
ret = CDB___db_panic(dbenv, EINVAL);
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If the existing chain is too short, pop a free page from
|
||
|
* the free pages database.
|
||
|
*/
|
||
|
memset(&key, '\0', sizeof(DBT));
|
||
|
memset(&data, '\0', sizeof(DBT));
|
||
|
|
||
|
key.data = &recno;
|
||
|
key.size = sizeof(recno);
|
||
|
|
||
|
if((ret = db->get(db, NULL, &key, &data, DB_SET_RECNO)) != 0) {
|
||
|
/*
|
||
|
* If the free list is empty, create a new page.
|
||
|
*/
|
||
|
#ifdef DEBUG_CMPR
|
||
|
fprintf(stderr,"CDB___memp_cmpr_alloc:: weakcmpr free page pool empty, allocating\n");
|
||
|
#endif
|
||
|
if(ret == DB_NOTFOUND) {
|
||
|
DB_MPOOL *dbmp = dbmfp->dbmp;
|
||
|
ret = 0;
|
||
|
R_LOCK(dbenv, &dbmp->reginfo);
|
||
|
++dbmfp->mfp->last_pgno;
|
||
|
#ifdef DEBUG
|
||
|
word_monitor_set(WORD_MONITOR_PGNO, dbmfp->mfp->last_pgno);
|
||
|
#endif /* DEBUG */
|
||
|
*pgnop = dbmfp->mfp->last_pgno;
|
||
|
R_UNLOCK(dbenv, &dbmp->reginfo);
|
||
|
ret = 0;
|
||
|
} else {
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_alloc: unexpected error from weakcmpr base");
|
||
|
ret = CDB___db_panic(dbenv, ret);
|
||
|
}
|
||
|
} else {
|
||
|
if(key.size != sizeof(db_pgno_t)) {
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_alloc: unexpected key size from weakcmpr base (%d instead of %d)", key.size, sizeof(db_pgno_t));
|
||
|
ret = CDB___db_panic(dbenv, ret);
|
||
|
} else {
|
||
|
memcpy((char*)pgnop, (char*)key.data, key.size);
|
||
|
if((ret = db->del(db, NULL, &key, 0)) != 0) {
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_alloc: del error, got pgno %d", *pgnop);
|
||
|
ret = CDB___db_panic(dbenv, ret);
|
||
|
}
|
||
|
if(*pgnop == 0) {
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_alloc: unexpected pgno == 0");
|
||
|
ret = CDB___db_panic(dbenv, ret);
|
||
|
}
|
||
|
}
|
||
|
#ifdef DEBUG_CMPR
|
||
|
fprintf(stderr,"CDB___memp_cmpr_alloc:: reuse free page %d from weakcmpr\n", *pgnop);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
err:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CDB___memp_cmpr_free --
|
||
|
* Release a page used to store weak compression data.
|
||
|
*
|
||
|
* PUBLIC: int CDB___memp_cmpr_free __P((DB_MPOOLFILE *, db_pgno_t));
|
||
|
*/
|
||
|
int
|
||
|
CDB___memp_cmpr_free(dbmfp, pgno)
|
||
|
DB_MPOOLFILE *dbmfp;
|
||
|
db_pgno_t pgno;
|
||
|
{
|
||
|
int ret = 0;
|
||
|
DB_ENV *dbenv = dbmfp->dbmp->dbenv;
|
||
|
DB *db = dbmfp->cmpr_context.weakcmpr;
|
||
|
DBT key;
|
||
|
DBT data;
|
||
|
|
||
|
#ifdef DEBUG_CMPR
|
||
|
fprintf(stderr,"CDB___memp_cmpr_free:: freeing page (inserting into weakcmpr):%3d \n",pgno);
|
||
|
#endif
|
||
|
if(db == 0) {
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_free: dbmfp->cmpr_context.weakcmpr is null");
|
||
|
ret = CDB___db_panic(dbenv, EINVAL);
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
memset(&key, '\0', sizeof(DBT));
|
||
|
memset(&data, '\0', sizeof(DBT));
|
||
|
|
||
|
key.data = &pgno;
|
||
|
key.size = sizeof(db_pgno_t);
|
||
|
|
||
|
data.data = " ";
|
||
|
data.size = 1;
|
||
|
|
||
|
if((ret = db->put(db, 0, &key, &data, DB_NOOVERWRITE)) != 0) {
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_free: put failed for pgno = %d", pgno);
|
||
|
ret = CDB___db_panic(dbenv, ret);
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
err:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* CDB___memp_cmpr_alloc_chain --
|
||
|
* Allocate chain entry in BH
|
||
|
*
|
||
|
* PUBLIC: int CDB___memp_cmpr_alloc_chain __P((DB_MPOOL *, BH *));
|
||
|
*/
|
||
|
|
||
|
int
|
||
|
CDB___memp_cmpr_alloc_chain(dbmp, bhp, alloc_type)
|
||
|
DB_MPOOL *dbmp;
|
||
|
BH *bhp;
|
||
|
int alloc_type;
|
||
|
{
|
||
|
DB_ENV *dbenv = dbmp->dbenv;
|
||
|
int ret = 0;
|
||
|
if(!bhp->chain) {
|
||
|
int alloc_ret;
|
||
|
int alloc_length = sizeof(db_pgno_t)*(CMPR_MAX-1);
|
||
|
switch(alloc_type) {
|
||
|
case BH_CMPR_POOL:
|
||
|
{
|
||
|
MPOOL *mp = dbmp->reginfo.primary;
|
||
|
int n_cache = NCACHE(mp, bhp->pgno);
|
||
|
alloc_ret = CDB___memp_alloc(dbmp, &dbmp->c_reginfo[n_cache], NULL, alloc_length, NULL, (void *)(&bhp->chain));
|
||
|
F_SET(bhp, BH_CMPR_POOL);
|
||
|
}
|
||
|
break;
|
||
|
case BH_CMPR_OS:
|
||
|
alloc_ret = CDB___os_malloc(alloc_length, NULL, &bhp->chain);
|
||
|
F_SET(bhp, BH_CMPR_OS);
|
||
|
break;
|
||
|
default:
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_alloc_chain: unknown alloc type :%d", alloc_type);
|
||
|
ret = CDB___db_panic(dbenv, EINVAL);
|
||
|
goto err;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(alloc_ret) {
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_alloc_chain: memp_alloc %d bytes failed:%d", alloc_length, alloc_ret);
|
||
|
ret = CDB___db_panic(dbenv, EINVAL);
|
||
|
goto err;
|
||
|
}
|
||
|
memset((void *)bhp->chain, 0, alloc_length);
|
||
|
#if defined(DEBUG_CMPR) || defined(DEBUG_CMPR_ALLOC)
|
||
|
fprintf(stderr, "CDB___memp_cmpr_alloc_chain:: allocate chain in %s :%8x\n", (alloc_type == BH_CMPR_OS ? "malloc" : "shalloc"), bhp->chain);
|
||
|
#endif
|
||
|
} else {
|
||
|
#ifdef DEBUG_CMPR
|
||
|
fprintf(stderr, "CDB___memp_cmpr_alloc_chain:: existing chain:%8x\n", bhp->chain);
|
||
|
#endif
|
||
|
}
|
||
|
F_SET(bhp, BH_CMPR);
|
||
|
err:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CDB___memp_cmpr_free_chain --
|
||
|
* Free chain entry in BH
|
||
|
*
|
||
|
* PUBLIC: int CDB___memp_cmpr_free_chain __P((DB_MPOOL *, BH *));
|
||
|
*/
|
||
|
|
||
|
int
|
||
|
CDB___memp_cmpr_free_chain(dbmp, bhp)
|
||
|
DB_MPOOL *dbmp;
|
||
|
BH *bhp;
|
||
|
{
|
||
|
DB_ENV *dbenv = dbmp->dbenv;
|
||
|
|
||
|
if(F_ISSET(bhp, BH_CMPR)) {
|
||
|
if(bhp->chain) {
|
||
|
int alloc_length = sizeof(db_pgno_t)*(CMPR_MAX-1);
|
||
|
int alloc_type = bhp->flags & (BH_CMPR_POOL|BH_CMPR_OS);
|
||
|
switch(alloc_type) {
|
||
|
case BH_CMPR_POOL:
|
||
|
{
|
||
|
MPOOL *mp = dbmp->reginfo.primary;
|
||
|
int n_cache = NCACHE(mp, bhp->pgno);
|
||
|
CDB___db_shalloc_free(dbmp->c_reginfo[n_cache].addr, bhp->chain);
|
||
|
}
|
||
|
break;
|
||
|
case BH_CMPR_OS:
|
||
|
CDB___os_free(bhp->chain, alloc_length);
|
||
|
break;
|
||
|
default:
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_free_chain: unknown alloc type :%d", alloc_type);
|
||
|
return CDB___db_panic(dbenv, EINVAL);
|
||
|
break;
|
||
|
}
|
||
|
#if defined(DEBUG_CMPR) || defined(DEBUG_CMPR_ALLOC)
|
||
|
fprintf(stderr, "CDB___memp_cmpr_free_chain:: free chain in %s :%8x\n", (alloc_type == BH_CMPR_OS ? "malloc" : "shalloc"), bhp->chain);
|
||
|
#endif
|
||
|
bhp->chain = NULL;
|
||
|
} else {
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_free_chain: BH_CMPR set but null bhp->chain");
|
||
|
return CDB___db_panic(dbenv, EINVAL);
|
||
|
}
|
||
|
} else if(bhp->chain) {
|
||
|
CDB___db_err(dbenv, "CDB___memp_cmpr_free_chain: BH_CMPR not set but bhp->chain not null");
|
||
|
return CDB___db_panic(dbenv, EINVAL);
|
||
|
}
|
||
|
|
||
|
F_CLR(bhp, BH_CMPR | BH_CMPR_OS | BH_CMPR_POOL);
|
||
|
|
||
|
return 0;
|
||
|
}
|