00001 /*- 00002 * See the file LICENSE for redistribution information. 00003 * 00004 * Copyright (c) 1999, 2000 00005 * Loic Dachary. All rights reserved. 00006 * 00007 * TODO: 00008 * Keith Bostic says: 00009 * The only change I'd probably think about is if 00010 * we should merge the call to CDB___memp_pg and CDB___memp_cmpr -- kind 00011 * of a stack of page modification routines, that sits on top of 00012 * CDB___os_io. That's a bigger change, but it's probably cleaner 00013 * in the long-run. 00014 * 00015 * Pending questions: 00016 * 00017 * The CMPR structure contains binary data. Should we store them in network order ? 00018 * How is this related to DB_AM_SWAP ? 00019 * 00020 * In CDB___memp_cmpr, niop is always multiplied by compression factor for page 0. 00021 * I see no problems with this but it's a bit awkward. 00022 * 00023 * In __memp_cmpr_page, the page built fills some fields of the PAGE structure 00024 * others are set to 0. I'm not 100% sure this is enough. It should only impact 00025 * utilities that read pages by incrementing pgno. Only stat does this an it's 00026 * enough for it. I've not found any other context where these fake pages are 00027 * used. 00028 * 00029 */ 00030 00031 #include "config.h" 00032 00033 #ifndef lint 00034 static const char sccsid[] = "@(#)mp_cmpr.c 1.1 (Senga) 01/08/99"; 00035 #endif /* not lint */ 00036 00037 #ifndef NO_SYSTEM_INCLUDES 00038 #include <sys/types.h> 00039 #include <string.h> 00040 #include <errno.h> 00041 #endif 00042 00043 #include "db_int.h" 00044 #include "db_page.h" 00045 #include "shqueue.h" 00046 #include "db_shash.h" 00047 #include "mp.h" 00048 #include "db_page.h" 00049 #include "common_ext.h" 00050 00051 #ifdef DEBUG 00052 #include "WordMonitor.h" 00053 #endif /* DEBUG */ 00054 00055 #if 0 00056 #define DEBUG_CMPR 1 00057 #endif 00058 #if 0 00059 #define DEBUG_CMPR_ALLOC 1 00060 #endif 00061 00062 /* 00063 * Helpers declarations. 00064 */ 00065 static int __memp_cmpr_page __P((DB_MPOOLFILE *, CMPR *, DB_IO *, ssize_t *)); 00066 00067 /* 00068 * Maximum chain length 00069 */ 00070 #define CMPR_MAX (dbenv->mp_cmpr_info->max_npages) 00071 00072 #define CMPR_MULTIPLY(n) ((n) << (dbenv->mp_cmpr_info->coefficient)) 00073 #define CMPR_DIVIDE(n) ((n) >> (dbenv->mp_cmpr_info->coefficient)) 00074 00075 #ifdef HAVE_LIBZ 00076 static DB_CMPR_INFO default_cmpr_info = { 00077 CDB___memp_cmpr_deflate, 00078 CDB___memp_cmpr_inflate, 00079 1, 00080 3, 00081 NULL 00082 }; 00083 #else /* HAVE_LIBZ */ 00084 static DB_CMPR_INFO default_cmpr_info = { 00085 0, 00086 0, 00087 0, 00088 0, 00089 NULL 00090 }; 00091 #endif /* HAVE_LIBZ */ 00092 00093 /* 00094 * Entry point. Functionaly equivalent to CDB___os_io. 00095 * Compress/uncompress pages before returning them or writing them to disk. 00096 */ 00097 00098 /* 00099 * CDB___memp_cmpr -- 00100 * Transparent compression read/write 00101 * 00102 * PUBLIC: int CDB___memp_cmpr __P((DB_MPOOLFILE *, BH *, DB_IO *, int, ssize_t *)); 00103 */ 00104 int 00105 CDB___memp_cmpr(dbmfp, bhp, db_io, flag, niop) 00106 DB_MPOOLFILE *dbmfp; 00107 BH *bhp; 00108 DB_IO *db_io; 00109 int flag; 00110 ssize_t *niop; 00111 { 00112 size_t orig_pagesize = db_io->pagesize; 00113 db_pgno_t orig_pgno = db_io->pgno; 00114 size_t orig_bytes = db_io->bytes; 00115 DB_ENV *dbenv = dbmfp->dbmp->dbenv; 00116 int ret = 0; 00117 00118 db_io->pagesize = CMPR_DIVIDE(db_io->pagesize); 00119 db_io->bytes = CMPR_DIVIDE(db_io->bytes); 00120 00121 /* 00122 * Page 0 is a special case. It contains the metadata information 00123 * (at most 256 bytes) and must not be compressed because it is read 00124 * with CDB___os_read and not CDB___os_io. This read is done before 00125 * any memory pool structure is initialized, we therefore have no 00126 * chance to trap it anywhere but here. 00127 */ 00128 switch (flag) { 00129 case DB_IO_READ: 00130 if(db_io->pgno == PGNO_BASE_MD) { 00131 ret = CDB___os_io(dbenv, db_io, DB_IO_READ, niop); 00132 *niop = CMPR_MULTIPLY(*niop); 00133 } else 00134 ret = CDB___memp_cmpr_read(dbmfp, bhp, db_io, niop); 00135 break; 00136 case DB_IO_WRITE: 00137 if(db_io->pgno == PGNO_BASE_MD) { 00138 /* 00139 * Write a copy of the DBMETA information at 00140 * 256, 512, 1024, 2048, 4096, ... up to the actually required page size. 00141 * This ensure that the DBMETA information will be found without knowing 00142 * the actual page size used in the file. 00143 * !! Assume that PGNO_BASE_MD == 1 00144 */ 00145 size_t required = db_io->pagesize; 00146 size_t orig_bytes = db_io->bytes; 00147 db_io->bytes = DBMETASIZE; 00148 for(db_io->pagesize = DBMETASIZE; db_io->pagesize < required; db_io->pagesize <<= 1) { 00149 ret = CDB___os_io(dbenv, db_io, DB_IO_WRITE, niop); 00150 if(ret != 0 || *niop != DBMETASIZE) 00151 break; 00152 } 00153 db_io->bytes = orig_bytes; 00154 db_io->pagesize = required; 00155 if(ret == 0) 00156 ret = CDB___os_io(dbenv, db_io, DB_IO_WRITE, niop); 00157 *niop = CMPR_MULTIPLY(*niop); 00158 } else 00159 ret = CDB___memp_cmpr_write(dbmfp, bhp, db_io, niop); 00160 break; 00161 } 00162 00163 db_io->pgno = orig_pgno; 00164 db_io->pagesize = orig_pagesize; 00165 db_io->bytes = orig_bytes; 00166 00167 return ret; 00168 } 00169 00170 /* 00171 * CDB___memp_cmpr_read_meta -- 00172 * Transparent compression read page containing meta header 00173 */ 00174 int 00175 CDB___memp_cmpr_read_meta(dbenv, fhp, buff, buff_length, nrp) 00176 DB_ENV *dbenv; 00177 DB_FH *fhp; 00178 void *buff; 00179 size_t buff_length; 00180 ssize_t *nrp; 00181 { 00182 CMPR cmpr; 00183 int ret; 00184 int i; 00185 00186 if((ret = CDB___os_read(dbenv, fhp, buff, buff_length, nrp)) != 0) 00187 goto err; 00188 00189 if(*nrp != buff_length) 00190 goto err; 00191 00192 /* 00193 * Read the cmpr header from page. 00194 */ 00195 memcpy(&cmpr, buff, sizeof(CMPR)); 00196 00197 /* 00198 * If not at the beginning of compressed page chain, build 00199 * a fake page. 00200 */ 00201 if(F_ISSET(&cmpr, DB_CMPR_FREE) || F_ISSET(&cmpr, DB_CMPR_INTERNAL)) { 00202 ret = CDB___db_panic(dbenv, EINVAL); 00203 goto err; 00204 } 00205 00206 for(i = 0; i < buff_length - (DB_CMPR_OVERHEAD + 1); i++) 00207 ((char*)buff)[i] = ((char*)buff)[i + (DB_CMPR_OVERHEAD + 1)]; 00208 00209 err: 00210 return ret; 00211 } 00212 00213 /* 00214 * CDB___memp_cmpr_read -- 00215 * Transparent compression read 00216 * 00217 * PUBLIC: int CDB___memp_cmpr_read __P((DB_MPOOLFILE *, BH *, DB_IO *, ssize_t *)); 00218 */ 00219 int 00220 CDB___memp_cmpr_read(dbmfp, bhp, db_io, niop) 00221 DB_MPOOLFILE *dbmfp; 00222 BH *bhp; 00223 DB_IO *db_io; 00224 ssize_t *niop; 00225 { 00226 CMPR cmpr; 00227 int ret; 00228 int chain = 0; 00229 u_int8_t *buffcmpr = 0; 00230 int buffcmpr_length = 0; 00231 int chain_length = 0; 00232 db_pgno_t first_pgno = db_io->pgno; 00233 DB_ENV *dbenv = dbmfp->dbmp->dbenv; 00234 DB_CMPR_INFO *cmpr_info = dbenv->mp_cmpr_info; 00235 /* 00236 * By default the compression does not use too much space, 00237 * hence the chain is empty. 00238 */ 00239 F_CLR(bhp, BH_CMPR); 00240 00241 /* 00242 * Read first page (if no overflow, this is the only one) 00243 */ 00244 ret = CDB___os_io(dbenv, db_io, DB_IO_READ, niop); 00245 00246 /* 00247 * An error or partial read on the first page means that we're not 00248 * going anywhere. 00249 */ 00250 if(ret || *niop < db_io->pagesize) 00251 goto err; 00252 00253 /* 00254 * Read the cmpr header from page. 00255 */ 00256 memcpy(&cmpr, db_io->buf, sizeof(CMPR)); 00257 00258 /* 00259 * If not at the beginning of compressed page chain, build 00260 * a fake page. 00261 */ 00262 if(F_ISSET(&cmpr, DB_CMPR_FREE) || F_ISSET(&cmpr, DB_CMPR_INTERNAL)) { 00263 ret = __memp_cmpr_page(dbmfp, &cmpr, db_io, niop); 00264 goto err; 00265 } 00266 00267 /* 00268 * Sanity check. Happens if file corrupted. 00269 */ 00270 if(!F_ISSET(&cmpr, DB_CMPR_FIRST)) { 00271 CDB___db_err(dbmfp->dbmp->dbenv, "CDB___memp_cmpr_read: expected DB_CMPR_FIRST flag set at pgno = %ld", db_io->pgno); 00272 ret = CDB___db_panic(dbmfp->dbmp->dbenv, EINVAL); 00273 goto err; 00274 } 00275 00276 if((ret = CDB___os_malloc(dbenv, db_io->pagesize * CMPR_MAX, NULL, &buffcmpr)) != 0) 00277 goto err; 00278 00279 do { 00280 /* 00281 * Read the first part of the compressed data from page. 00282 */ 00283 memcpy(buffcmpr + buffcmpr_length, DB_CMPR_DATA(db_io), DB_CMPR_PAGESIZE(db_io)); 00284 buffcmpr_length += DB_CMPR_PAGESIZE(db_io); 00285 00286 /* 00287 * Flag must only contain FIRST|INTERNAL and/or CHAIN. If other bits are 00288 * set, the data is corrupted. Removing the FIRST|INTERNAL bits and checking 00289 * the CHAIN bit with == instead of F_ISSET verify this. 00290 */ 00291 F_CLR(&cmpr, DB_CMPR_FIRST | DB_CMPR_INTERNAL); 00292 chain = cmpr.flags; 00293 00294 if(chain == DB_CMPR_CHAIN) { 00295 /* 00296 * Overflow Case. Continue reading data from extra pages. 00297 */ 00298 00299 chain_length++; 00300 if(chain_length >= CMPR_MAX) { 00301 CDB___db_err(dbmfp->dbmp->dbenv, "CDB___memp_cmpr_read: compression chain too long at pgno = %ld", db_io->pgno); 00302 ret = CDB___db_panic(dbmfp->dbmp->dbenv, EINVAL); 00303 goto err; 00304 } 00305 00306 if(cmpr.next == 0) { 00307 CDB___db_err(dbmfp->dbmp->dbenv, "CDB___memp_cmpr_read: cmpr.next is null at pgno = %ld", chain, db_io->pgno); 00308 ret = CDB___db_panic(dbmfp->dbmp->dbenv, EINVAL); 00309 goto err; 00310 } 00311 /* 00312 * Keep the chain in buffer header. 00313 */ 00314 CDB___memp_cmpr_alloc_chain(dbmfp->dbmp, bhp, BH_CMPR_POOL); 00315 00316 bhp->chain[chain_length - 1] = cmpr.next; 00317 db_io->pgno = cmpr.next; 00318 /* 00319 * Read data from extra page. 00320 */ 00321 if((ret = CDB___os_io(dbenv, db_io, DB_IO_READ, niop)) != 0 || 00322 *niop != db_io->pagesize) { 00323 ret = EIO; 00324 goto err; 00325 } 00326 /* 00327 * Read the cmpr header from this extra page 00328 */ 00329 memcpy(&cmpr, db_io->buf, sizeof(CMPR)); 00330 } else if(chain != 0) { 00331 CDB___db_err(dbmfp->dbmp->dbenv, "CDB___memp_cmpr_read: unexpected compression flag value 0x%x at pgno = %ld", chain, db_io->pgno); 00332 ret = CDB___db_panic(dbmfp->dbmp->dbenv, ret); 00333 goto err; 00334 } else if(cmpr.next != 0) { 00335 CDB___db_err(dbmfp->dbmp->dbenv, "CDB___memp_cmpr_read: cmpr.next is not null at pgno = %ld", chain, db_io->pgno); 00336 ret = CDB___db_panic(dbmfp->dbmp->dbenv, ret); 00337 goto err; 00338 } 00339 } while(chain); 00340 00341 /* 00342 * We gathered all the compressed data in buffcmpr, inflate it. 00343 */ 00344 { 00345 switch((*buffcmpr) & TYPE_MASK) { 00346 case P_HASHMETA: 00347 case P_BTREEMETA: 00348 case P_QAMMETA: 00349 case P_INVALID: 00350 memcpy(db_io->buf, buffcmpr + sizeof(char), 255); 00351 break; 00352 default: 00353 if((ret = (*cmpr_info->uncompress)(dbenv, buffcmpr, buffcmpr_length, db_io->buf, CMPR_MULTIPLY(db_io->pagesize), cmpr_info->user_data)) != 0) { 00354 CDB___db_err(dbmfp->dbmp->dbenv, "CDB___memp_cmpr_read: unable to uncompress page at pgno = %ld", first_pgno); 00355 ret = CDB___db_panic(dbmfp->dbmp->dbenv, ret); 00356 goto err; 00357 } 00358 break; 00359 } 00360 } 00361 #ifdef DEBUG 00362 { 00363 int ratio = buffcmpr_length > 0 ? (CMPR_MULTIPLY(db_io->pagesize) / buffcmpr_length) : 0; 00364 if(ratio > 10) ratio = 10; 00365 word_monitor_add(DB_MONITOR(dbenv), WORD_MONITOR_COMPRESS_01 + ratio, 1); 00366 } 00367 #endif /* DEBUG */ 00368 00369 *niop = CMPR_MULTIPLY(db_io->pagesize); 00370 00371 err: 00372 #ifdef DEBUG_CMPR 00373 if(chain_length > 0) { 00374 int i; 00375 fprintf(stderr,"CDB___memp_cmpr_read:: chain_length (number of overflow pages):%2d\n",chain_length); 00376 fprintf(stderr,"CDB___memp_cmpr_read:: chain "); 00377 for(i = 0; i < chain_length; i++) 00378 fprintf(stderr, "%d, ", bhp->chain[i]); 00379 fprintf(stderr, "\n"); 00380 } 00381 #endif 00382 if(buffcmpr) CDB___os_free(buffcmpr, 0); 00383 return ret; 00384 } 00385 00386 /* 00387 * CDB___memp_cmpr_write -- 00388 * Transparent compression write 00389 * 00390 * PUBLIC: int CDB___memp_cmpr_write __P((DB_MPOOLFILE *, BH *, DB_IO *, ssize_t *)); 00391 */ 00392 int 00393 CDB___memp_cmpr_write(dbmfp, bhp, db_io, niop) 00394 DB_MPOOLFILE *dbmfp; 00395 BH *bhp; 00396 DB_IO *db_io; 00397 ssize_t *niop; 00398 { 00399 CMPR cmpr; 00400 int chain_length = 0; 00401 int first_nonreused_chain_pos = 0; 00402 int ret; 00403 u_int8_t *buffcmpr = 0; 00404 u_int8_t *buffp; 00405 int buffcmpr_length; 00406 u_int8_t *orig_buff = db_io->buf; 00407 DB_ENV *dbenv = dbmfp->dbmp->dbenv; 00408 DB_CMPR_INFO *cmpr_info = dbenv->mp_cmpr_info; 00409 00410 if((ret = CDB___os_malloc(dbenv, CMPR_MULTIPLY(db_io->bytes), NULL, &db_io->buf)) != 0) 00411 goto err; 00412 00413 /* 00414 * Call the compression function, except for META pages (at most 256 bytes) 00415 */ 00416 { 00417 PAGE* pp = (PAGE*)orig_buff; 00418 switch(TYPE(pp)) { 00419 case P_HASHMETA: 00420 case P_BTREEMETA: 00421 case P_QAMMETA: 00422 case P_INVALID: 00423 /* 00424 * Compressed meta is type byte + 255 bytes (the largest META info 00425 * is smaller than 255 bytes). 00426 */ 00427 buffcmpr_length = 256; 00428 if ((ret = CDB___os_malloc(dbenv, buffcmpr_length, NULL, &buffcmpr)) != 0) 00429 goto err; 00430 buffcmpr[0] = TYPE_TAGS(pp); 00431 memcpy(buffcmpr + 1, orig_buff, 255); 00432 break; 00433 default: 00434 if((ret = (*cmpr_info->compress)(dbenv, orig_buff, CMPR_MULTIPLY(db_io->pagesize), &buffcmpr, &buffcmpr_length, cmpr_info->user_data)) != 0) { 00435 CDB___db_err(dbmfp->dbmp->dbenv, "CDB___memp_cmpr_write: unable to compress page at pgno = %ld", db_io->pgno); 00436 ret = CDB___db_panic(dbmfp->dbmp->dbenv, ret); 00437 goto err; 00438 } 00439 } 00440 } 00441 #ifdef DEBUG 00442 { 00443 int ratio = buffcmpr_length > 0 ? (CMPR_MULTIPLY(db_io->pagesize) / buffcmpr_length) : 0; 00444 if(ratio > 10) ratio = 10; 00445 word_monitor_add(DB_MONITOR(dbenv), WORD_MONITOR_COMPRESS_01 + ratio, 1); 00446 } 00447 #endif /* DEBUG */ 00448 00449 /* 00450 * This can never happen. 00451 */ 00452 if(buffcmpr_length > DB_CMPR_PAGESIZE(db_io) * CMPR_MAX) { 00453 CDB___db_err(dbmfp->dbmp->dbenv, "CDB___memp_cmpr_write: compressed data is too big at pgno = %ld", db_io->pgno); 00454 ret = CDB___db_panic(dbmfp->dbmp->dbenv, EINVAL); 00455 goto err; 00456 } 00457 00458 buffp = buffcmpr; 00459 cmpr.flags = DB_CMPR_FIRST; 00460 cmpr.next = 0; 00461 00462 /* write pages until the whole compressed data is written */ 00463 do { 00464 int length = buffcmpr_length - (buffp - buffcmpr); 00465 int copy_length = length > DB_CMPR_PAGESIZE(db_io) ? DB_CMPR_PAGESIZE(db_io) : length; 00466 /* 00467 * We handle serious compression stuff only if we need to. 00468 * overflow! the compressed buffer is too big -> get extra page 00469 */ 00470 if(length > copy_length) { 00471 chain_length++; 00472 if(chain_length >= CMPR_MAX) { 00473 CDB___db_err(dbmfp->dbmp->dbenv, "CDB___memp_cmpr_write: chain_length overflow"); 00474 ret = CDB___db_panic(dbmfp->dbmp->dbenv, EINVAL); 00475 goto err; 00476 } 00477 F_SET(&cmpr, DB_CMPR_CHAIN); 00478 if((ret = CDB___memp_cmpr_alloc(dbmfp, &cmpr.next, db_io->pagesize, bhp, &first_nonreused_chain_pos)) != 0) 00479 goto err; 00480 CDB___memp_cmpr_alloc_chain(dbmfp->dbmp, bhp, BH_CMPR_OS); 00481 bhp->chain[chain_length - 1] = cmpr.next; 00482 } 00483 /* write in the cmpr header */ 00484 memcpy(db_io->buf, &cmpr, DB_CMPR_OVERHEAD); 00485 /* write in what's left of the compressed buffer (and that also fits in) */ 00486 memcpy(db_io->buf + DB_CMPR_OVERHEAD, buffp, copy_length); 00487 buffp += copy_length; 00488 /* actual output */ 00489 if((ret = CDB___os_io(dbenv, db_io, DB_IO_WRITE, niop)) != 0 || 00490 *niop != db_io->pagesize) { 00491 ret = EIO; 00492 goto err; 00493 } 00494 db_io->pgno = cmpr.next; 00495 cmpr.flags = DB_CMPR_INTERNAL; 00496 cmpr.next = 0; 00497 } while(buffp - buffcmpr < buffcmpr_length); 00498 00499 #ifdef DEBUG_CMPR 00500 fprintf(stderr,"CDB___memp_cmpr_write:: chain_length (number of overflow pages):%2d\n",chain_length); 00501 if(chain_length > 0) { 00502 int i; 00503 fprintf(stderr,"CDB___memp_cmpr_write:: chain "); 00504 for(i = 0; i < chain_length; i++) 00505 fprintf(stderr, "%d, ", bhp->chain[i]); 00506 fprintf(stderr, "\n"); 00507 } 00508 #endif 00509 /* 00510 * If the chain was not completely reused, free the remaining pages (the page compression 00511 * rate is better). 00512 */ 00513 if(F_ISSET(bhp, BH_CMPR) && first_nonreused_chain_pos >= 0) { 00514 int i; 00515 for(i = first_nonreused_chain_pos; i < (CMPR_MAX - 1) && bhp->chain[i]; i++) { 00516 if((ret = CDB___memp_cmpr_free(dbmfp, bhp->chain[i], db_io->pagesize)) != 0) 00517 goto err; 00518 bhp->chain[i] = 0; 00519 } 00520 } 00521 00522 CDB___memp_cmpr_free_chain(dbmfp->dbmp, bhp); 00523 00524 /* 00525 * In case of success, always pretend that we exactly wrote the 00526 * all bytes of the original pagesize. 00527 */ 00528 *niop = CMPR_MULTIPLY(db_io->pagesize); 00529 00530 err: 00531 CDB___os_free(db_io->buf, 0); 00532 db_io->buf = orig_buff; 00533 if(buffcmpr) CDB___os_free(buffcmpr, 0); 00534 00535 return ret; 00536 } 00537 00538 /* 00539 * Helpers 00540 */ 00541 00542 /* 00543 * __memp_cmpr_page -- 00544 * Build a fake page. This function is a CDB___memp_cmpr_read helper. 00545 * 00546 */ 00547 static int 00548 __memp_cmpr_page(dbmfp, cmpr, db_io, niop) 00549 DB_MPOOLFILE *dbmfp; 00550 CMPR *cmpr; 00551 DB_IO *db_io; 00552 ssize_t *niop; 00553 { 00554 DB_ENV *dbenv = dbmfp->dbmp->dbenv; 00555 int ret = 0; 00556 PAGE page; 00557 00558 memset((char*)&page, '0円', sizeof(PAGE)); 00559 00560 page.pgno = db_io->pgno; 00561 page.type = F_ISSET(cmpr, DB_CMPR_FREE) ? P_CMPR_FREE : P_CMPR_INTERNAL; 00562 00563 /* 00564 * Sanity check 00565 */ 00566 if(db_io->pagesize < sizeof(PAGE)) { 00567 ret = ENOMEM; 00568 goto err; 00569 } 00570 00571 memcpy(db_io->buf, (char*)&page, sizeof(PAGE)); 00572 00573 *niop = CMPR_MULTIPLY(db_io->pagesize); 00574 00575 err: 00576 00577 return ret; 00578 } 00579 00580 #ifdef HAVE_LIBZ 00581 #include "zlib.h" 00582 #endif /* HAVE_LIBZ */ 00583 00584 /* 00585 * CDB___memp_cmpr_inflate -- 00586 * Decompress buffer 00587 * 00588 * PUBLIC: int CDB___memp_cmpr_inflate __P((const u_int8_t *, int, u_int8_t *, int, void *)); 00589 */ 00590 int 00591 CDB___memp_cmpr_inflate(dbenv, inbuff, inbuff_length, outbuff, outbuff_length, user_data) 00592 DB_ENV *dbenv; 00593 const u_int8_t* inbuff; 00594 int inbuff_length; 00595 u_int8_t* outbuff; 00596 int outbuff_length; 00597 void *user_data; 00598 { 00599 #ifdef HAVE_LIBZ 00600 int ret = 0; 00601 z_stream c_stream; 00602 00603 c_stream.zalloc=(alloc_func)0; 00604 c_stream.zfree=(free_func)0; 00605 c_stream.opaque=(voidpf)0; 00606 c_stream.next_in = (Bytef*)inbuff; 00607 c_stream.avail_in = inbuff_length; 00608 c_stream.next_out = outbuff; 00609 c_stream.avail_out = outbuff_length; 00610 00611 if(inflateInit(&c_stream) != Z_OK || 00612 inflate(&c_stream, Z_FINISH) != Z_STREAM_END || 00613 inflateEnd(&c_stream) != Z_OK) 00614 ret = EIO; 00615 00616 /* 00617 * The uncompressed data must *exactly* fill outbuff_length. 00618 */ 00619 if(c_stream.avail_out != 0) 00620 ret = EIO; 00621 00622 return ret; 00623 #else /* HAVE_LIBZ */ 00624 return EINVAL; 00625 #endif /* HAVE_LIBZ */ 00626 } 00627 00628 00629 00630 /* 00631 * CDB___memp_cmpr_deflate -- 00632 * Compress buffer 00633 * 00634 * PUBLIC: int CDB___memp_cmpr_deflate __P((const u_int8_t *, int, u_int8_t **, int*, void *)); 00635 */ 00636 int 00637 CDB___memp_cmpr_deflate(dbenv, inbuff, inbuff_length, outbuffp, outbuff_lengthp, user_data) 00638 DB_ENV* dbenv; 00639 const u_int8_t* inbuff; 00640 int inbuff_length; 00641 u_int8_t** outbuffp; 00642 int* outbuff_lengthp; 00643 void *user_data; 00644 { 00645 #ifdef HAVE_LIBZ 00646 int ret = 0; 00647 int r; 00648 z_stream c_stream; 00649 u_int8_t* outbuff; 00650 00651 /* 00652 * Z_FINISH can be used immediately after deflateInit if all the compression 00653 * is to be done in a single step. In this case, avail_out must be at least 00654 * 0.1% larger than avail_in plus 12 bytes. If deflate does not return 00655 * Z_STREAM_END, then it must be called again as described above. 00656 * 00657 * !!! 00658 * In order to avoid division by 1000, divide by 512 (2^9) using shift. 00659 * That is, make the buffer 0.2% larger. 00660 */ 00661 int outbuff_length = inbuff_length + (inbuff_length >> 9) + 12; 00662 00663 *outbuffp = 0; 00664 *outbuff_lengthp = 0; 00665 00666 if(CDB___os_malloc(dbenv, outbuff_length, NULL, &outbuff) != 0) { 00667 ret = ENOMEM; 00668 goto err; 00669 } 00670 00671 /* 00672 * Clear possible garbage in the page 00673 */ 00674 { 00675 PAGE* pg = (PAGE*)inbuff; 00676 switch(TYPE(pg)) { 00677 case P_IBTREE: 00678 case P_LBTREE: 00679 memset((char*)(inbuff + LOFFSET(pg)), '0円', P_FREESPACE(pg)); 00680 break; 00681 } 00682 } 00683 00684 c_stream.zalloc=(alloc_func)0; 00685 c_stream.zfree=(free_func)0; 00686 c_stream.opaque=(voidpf)0; 00687 00688 if(deflateInit(&c_stream, Z_DEFAULT_COMPRESSION) != Z_OK) { 00689 ret = EIO; 00690 goto err; 00691 } 00692 00693 c_stream.next_in = (Bytef*)inbuff; 00694 c_stream.avail_in = inbuff_length; 00695 c_stream.next_out = outbuff; 00696 c_stream.avail_out = outbuff_length; 00697 00698 while((r = deflate(&c_stream, Z_FINISH)) != Z_STREAM_END && r == Z_OK) 00699 ; 00700 00701 if(r != Z_STREAM_END) 00702 ret = EIO; 00703 00704 if(deflateEnd(&c_stream) != Z_OK) 00705 ret = EIO; 00706 00707 if(ret == 0) { 00708 *outbuffp = outbuff; 00709 *outbuff_lengthp = outbuff_length - c_stream.avail_out; 00710 } else { 00711 CDB___os_free(outbuff, outbuff_length); 00712 } 00713 #ifdef DEBUG_CMPR 00714 fprintf(stderr,"CDB___memp_cmpr_deflate:: compress %d bytes to %d \n", inbuff_length, *outbuff_lengthp); 00715 #endif 00716 00717 err: 00718 return ret; 00719 #else /* HAVE_LIBZ */ 00720 return EINVAL; 00721 #endif /* HAVE_LIBZ */ 00722 } 00723 00724 00725 00726 /* 00727 * __memp_cmpr_info_valid -- 00728 * Compute compressed page size 00729 */ 00730 static int 00731 __memp_cmpr_info_valid(dbenv,cmpr_info) 00732 DB_ENV *dbenv; 00733 DB_CMPR_INFO *cmpr_info; 00734 { 00735 int ret = 0; 00736 if(!cmpr_info ) { 00737 CDB___db_err(dbenv, "__memp_cmpr_info_valid: cmpr_info == NULL"); 00738 ret = CDB___db_panic(dbenv, EINVAL); 00739 goto err; 00740 } 00741 00742 if(!cmpr_info->compress ) { 00743 CDB___db_err(dbenv, "__memp_cmpr_info_valid: compress == NULL!"); 00744 ret = CDB___db_panic(dbenv, EINVAL); 00745 goto err; 00746 } 00747 00748 if(!cmpr_info->uncompress ) { 00749 CDB___db_err(dbenv, "__memp_cmpr_info_valid: uncompress == NULL!"); 00750 ret = CDB___db_panic(dbenv, EINVAL); 00751 goto err; 00752 } 00753 00754 if(cmpr_info->coefficient == 0 || cmpr_info->coefficient > 5 ) { 00755 CDB___db_err(dbenv, "__memp_cmpr_info_valid: coefficient should be > 0 and < 5 coefficient=%d ", cmpr_info->coefficient); 00756 ret = CDB___db_panic(dbenv, EINVAL); 00757 goto err; 00758 } 00759 00760 if(cmpr_info->max_npages == 0 || cmpr_info->max_npages > 128 ) { 00761 CDB___db_err(dbenv, "__memp_cmpr_info_valid: max_npages should be > 0 and < 128 max_npages=%d ", cmpr_info->max_npages); 00762 ret = CDB___db_panic(dbenv, EINVAL); 00763 goto err; 00764 } 00765 err: 00766 return ret; 00767 } 00768 00769 /* 00770 * __memp_cmpr_coefficient -- 00771 * 00772 * PUBLIC: u_int8_t CDB___memp_cmpr_coefficient __P((DB_ENV *dbenv)); 00773 */ 00774 u_int8_t 00775 CDB___memp_cmpr_coefficient(dbenv) 00776 DB_ENV *dbenv; 00777 { 00778 u_int8_t ret = 0; 00779 00780 if(!dbenv || !dbenv->mp_cmpr_info) { 00781 ret = default_cmpr_info.coefficient; 00782 } else { 00783 __memp_cmpr_info_valid(dbenv, dbenv->mp_cmpr_info); 00784 ret = dbenv->mp_cmpr_info->coefficient; 00785 } 00786 00787 return (ret); 00788 } 00789 00790 /* 00791 * Initialisation of page compression 00792 */ 00793 00794 #define CMPR_META_NORMAL 0x01 00795 #define CMPR_META_COMPRESSED 0x02 00796 00797 typedef struct _cmprmeta { 00798 u_int32_t magic; /* 00-03: Magic number. */ 00799 db_pgno_t free; /* 04-07: First free page. */ 00800 } CMPRMETA; 00801 00802 int 00803 CDB___memp_cmpr_create(dbenv, fhp, pgsize, flags) 00804 DB_ENV *dbenv; 00805 DB_FH *fhp; 00806 size_t pgsize; 00807 int flags; 00808 { 00809 int ret; 00810 int count = 0; 00811 CMPRMETA meta; 00812 char* buffer; 00813 00814 if((ret = CDB___os_malloc(dbenv, pgsize, NULL, &buffer)) != 0) { 00815 CDB___db_err(dbenv, "CDB___memp_cmpr_create: os_malloc %d bytes failed:%d", pgsize, ret); 00816 ret = CDB___db_panic(dbenv, EINVAL); 00817 return ret; 00818 } 00819 00820 meta.magic = flags == MP_CMPR ? CMPR_META_COMPRESSED : CMPR_META_NORMAL; 00821 meta.free = PGNO_INVALID; 00822 00823 if((ret = CDB___os_seek(dbenv, fhp, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0) { 00824 CDB___db_err(dbenv, "CDB___memp_cmpr_create: seek to 0 error"); 00825 return CDB___db_panic(dbenv, ret); 00826 } 00827 memcpy(buffer, (char*)&meta, sizeof(CMPRMETA)); 00828 if((ret = CDB___os_write(dbenv, fhp, buffer, pgsize, &count)) < 0) { 00829 CDB___db_err(dbenv, "CDB___memp_cmpr_create: write error at 0"); 00830 return CDB___db_panic(dbenv, ret); 00831 } 00832 if(count != pgsize) { 00833 CDB___db_err(dbenv, "CDB___memp_cmpr_create: write error %d bytes instead of %d bytes", count, pgsize); 00834 return CDB___db_panic(dbenv, EINVAL); 00835 } 00836 CDB___os_free(buffer, pgsize); 00837 00838 return ret; 00839 } 00840 00841 /* 00842 * CDB___memp_cmpr_open -- 00843 * Cache the meta information about compression, initialize dbenv info. 00844 * 00845 * PUBLIC: int CDB___memp_cmpr_open __P((DB_ENV *, MPOOLFILE *, const char *)); 00846 */ 00847 int 00848 CDB___memp_cmpr_open(dbenv, mfp, path) 00849 DB_ENV *dbenv; 00850 MPOOLFILE *mfp; 00851 const char *path; 00852 { 00853 int ret; 00854 /* 00855 * Read compression meta information 00856 */ 00857 DB_FH fh; 00858 ssize_t count; 00859 CMPRMETA meta; 00860 00861 if((ret = CDB___os_open(dbenv, path, DB_OSO_RDONLY, 0, &fh)) != 0) { 00862 CDB___db_err(dbenv, "CDB___memp_cmpr_open: cannot open %s readonly", path); 00863 return CDB___db_panic(dbenv, ret); 00864 } 00865 00866 if((ret = CDB___os_read(dbenv, &fh, (void*)&meta, sizeof(CMPRMETA), &count)) != 0) { 00867 CDB___db_err(dbenv, "CDB___memp_cmpr_open: cannot read page 0"); 00868 ret = CDB___db_panic(dbenv, ret); 00869 goto err; 00870 } 00871 00872 if(count != sizeof(CMPRMETA)) { 00873 CDB___db_err(dbenv, "CDB___memp_cmpr_open: read error %d bytes instead of %d bytes", count, sizeof(CMPRMETA)); 00874 ret = CDB___db_panic(dbenv, EINVAL); 00875 goto err; 00876 } 00877 00878 if(meta.magic == CMPR_META_COMPRESSED) { 00879 mfp->flags |= MP_CMPR; 00880 mfp->cmpr_free = meta.free; 00881 00882 /* 00883 * Initialisation of cmpr_context 00884 */ 00885 if(!dbenv->mp_cmpr_info) { 00886 if(default_cmpr_info.compress == 0) { 00887 CDB___db_err(dbenv, "CDB___memp_cmpr_open: zlib compression not available, re-compile --with-zlib=DIR"); 00888 ret = CDB___db_panic(dbenv, EINVAL); 00889 goto err; 00890 } 00891 dbenv->mp_cmpr_info = &default_cmpr_info; 00892 } 00893 /* 00894 * Check if cmpr_info is sane 00895 */ 00896 if((ret = __memp_cmpr_info_valid(dbenv, dbenv->mp_cmpr_info))) 00897 goto err; 00898 } 00899 00900 err: 00901 CDB___os_closehandle(&fh); 00902 00903 return ret; 00904 } 00905 00906 /* 00907 * CDB___memp_cmpr_close -- 00908 * This is not really a close but a sync. It is called more than 00909 * once per file, specifically when opening subdatabases. The 00910 * file handle will be used afterwards, most of the time. 00911 * 00912 * PUBLIC: int CDB___memp_cmpr_close __P((DB_ENV *, DB_MPOOLFILE *)); 00913 */ 00914 int 00915 CDB___memp_cmpr_close(dbenv, dbmfp) 00916 DB_ENV *dbenv; 00917 DB_MPOOLFILE *dbmfp; 00918 { 00919 /* 00920 * If handle is READ/WRITE 00921 */ 00922 if(dbmfp->flags & MP_UPGRADE) { 00923 MPOOLFILE *mfp = dbmfp->mfp; 00924 DB_FH *fhp = &dbmfp->fh; 00925 size_t count = 0; 00926 int ret; 00927 00928 CMPRMETA meta; 00929 memset((char*)&meta, '0円', sizeof(CMPRMETA)); 00930 00931 meta.magic = mfp->flags & MP_CMPR ? CMPR_META_COMPRESSED : CMPR_META_NORMAL; 00932 if(mfp->flags & MP_CMPR) 00933 meta.free = mfp->cmpr_free; 00934 00935 if((ret = CDB___os_seek(dbenv, fhp, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0) { 00936 CDB___db_err(dbenv, "CDB___memp_cmpr_close: seek to 0 error"); 00937 return CDB___db_panic(dbenv, ret); 00938 } 00939 00940 if((ret = CDB___os_write(dbenv, fhp, (void*)&meta, sizeof(CMPRMETA), &count)) < 0) { 00941 CDB___db_err(dbenv, "CDB___memp_cmpr_close: write error at 0"); 00942 return CDB___db_panic(dbenv, ret); 00943 } 00944 00945 if(count != sizeof(CMPRMETA)) { 00946 CDB___db_err(dbenv, "CDB___memp_cmpr_close: write error %d bytes instead of %d bytes", count, sizeof(CMPRMETA)); 00947 return CDB___db_panic(dbenv, EINVAL); 00948 } 00949 } 00950 00951 return 0; 00952 } 00953 00954 /* 00955 * CDB___memp_cmpr_alloc -- 00956 * Get a new free page to store weak compression data. 00957 * 00958 * PUBLIC: int CDB___memp_cmpr_alloc __P((DB_MPOOLFILE *, db_pgno_t *, size_t, BH *, int *)); 00959 */ 00960 int 00961 CDB___memp_cmpr_alloc(dbmfp, pgnop, pagesize, bhp, first_nonreused_chain_posp) 00962 DB_MPOOLFILE *dbmfp; 00963 db_pgno_t *pgnop; 00964 size_t pagesize; 00965 BH *bhp; 00966 int *first_nonreused_chain_posp; 00967 { 00968 DB_ENV *dbenv = dbmfp->dbmp->dbenv; 00969 int ret = 0; 00970 00971 #ifdef DEBUG_CMPR 00972 fprintf(stderr,"CDB___memp_cmpr_alloc:: bhp:%8x bhp->chain:%8x first_nonreused_chain_posp:%2d\n", bhp, bhp->chain, *first_nonreused_chain_posp); 00973 #endif 00974 if(F_ISSET(bhp, BH_CMPR) && bhp->chain == NULL) { 00975 CDB___db_err(dbenv, "CDB___memp_cmpr_alloc: BH_CMPR set and bhp->chain == NULL"); 00976 ret = CDB___db_panic(dbenv, EINVAL); 00977 goto err; 00978 } 00979 00980 if((*first_nonreused_chain_posp) >= (CMPR_MAX - 1)) { 00981 CDB___db_err(dbenv, "CDB___memp_cmpr_alloc: first_nonreused_chain_pos >= (CMPR_MAX - 1)"); 00982 ret = CDB___db_panic(dbenv, EINVAL); 00983 goto err; 00984 } 00985 00986 /* 00987 * If possible reuse an existing chain. 00988 */ 00989 if((*first_nonreused_chain_posp) >= 0 && F_ISSET(bhp, BH_CMPR) && bhp->chain[*first_nonreused_chain_posp]) { 00990 *pgnop = bhp->chain[*first_nonreused_chain_posp]; 00991 (*first_nonreused_chain_posp)++; 00992 #ifdef DEBUG_CMPR 00993 fprintf(stderr,"CDB___memp_cmpr_alloc:: reusing page in chain \n"); 00994 #endif 00995 } else { 00996 MPOOLFILE *mfp = dbmfp->mfp; 00997 DB_MPOOL *dbmp = dbmfp->dbmp; 00998 00999 /* all pages in bhp->chain are now reused */ 01000 (*first_nonreused_chain_posp) = -1; 01001 #ifdef DEBUG_CMPR 01002 fprintf(stderr,"CDB___memp_cmpr_alloc:: no more reusable pages in chain\n"); 01003 #endif 01004 R_LOCK(dbenv, dbmp->reginfo); 01005 if(mfp->cmpr_free == PGNO_INVALID) { 01006 #ifdef DEBUG_CMPR 01007 fprintf(stderr,"CDB___memp_cmpr_alloc:: free page pool empty, allocating\n"); 01008 #endif 01009 ret = 0; 01010 ++dbmfp->mfp->last_pgno; 01011 #ifdef DEBUG 01012 word_monitor_set(DB_MONITOR(dbenv), WORD_MONITOR_PGNO, dbmfp->mfp->last_pgno); 01013 #endif /* DEBUG */ 01014 *pgnop = dbmfp->mfp->last_pgno; 01015 } else { 01016 /* 01017 * Read the free page, save the next free page number. 01018 */ 01019 CMPR cmpr; 01020 size_t count; 01021 DB_FH *fhp = &dbmfp->fh; 01022 01023 *pgnop = mfp->cmpr_free; 01024 01025 if((ret = CDB___os_seek(dbenv, fhp, pagesize, *pgnop, 0, 0, DB_OS_SEEK_SET)) != 0) { 01026 CDB___db_err(dbenv, "CDB___memp_cmpr_alloc: seek error at %d", *pgnop); 01027 ret = CDB___db_panic(dbenv, ret); 01028 goto oops; 01029 } 01030 if((ret = CDB___os_read(dbenv, fhp, (void*)&cmpr, sizeof(CMPR), &count)) != 0) { 01031 CDB___db_err(dbenv, "CDB___memp_cmpr_alloc: read error at %d", *pgnop); 01032 ret = CDB___db_panic(dbenv, ret); 01033 goto oops; 01034 } 01035 if(count != sizeof(CMPR)) { 01036 CDB___db_err(dbenv, "CDB___memp_cmpr_alloc: read error %d bytes instead of %d bytes", count, sizeof(CMPR)); 01037 ret = CDB___db_panic(dbenv, ret); 01038 goto oops; 01039 } 01040 if(cmpr.flags != DB_CMPR_FREE) { 01041 CDB___db_err(dbenv, "CDB___memp_cmpr_alloc: got %d flags instead of DB_CMPR_FREE", cmpr.flags); 01042 ret = CDB___db_panic(dbenv, ret); 01043 goto oops; 01044 } 01045 mfp->cmpr_free = cmpr.next; 01046 01047 if(*pgnop == 0) { 01048 CDB___db_err(dbenv, "CDB___memp_cmpr_alloc: unexpected pgno == 0"); 01049 ret = CDB___db_panic(dbenv, ret); 01050 goto oops; 01051 } 01052 01053 #ifdef DEBUG_CMPR 01054 fprintf(stderr,"CDB___memp_cmpr_alloc:: reuse free page %d\n", *pgnop); 01055 #endif 01056 } 01057 oops: 01058 R_UNLOCK(dbenv, dbmp->reginfo); 01059 } 01060 err: 01061 return ret; 01062 } 01063 01064 /* 01065 * CDB___memp_cmpr_free -- 01066 * Release a page used to store weak compression data. 01067 * 01068 * PUBLIC: int CDB___memp_cmpr_free __P((DB_MPOOLFILE *, db_pgno_t)); 01069 */ 01070 int 01071 CDB___memp_cmpr_free(dbmfp, pgno, pagesize) 01072 DB_MPOOLFILE *dbmfp; 01073 db_pgno_t pgno; 01074 size_t pagesize; 01075 { 01076 int ret = 0; 01077 01078 DB_ENV *dbenv = dbmfp->dbmp->dbenv; 01079 MPOOLFILE *mfp = dbmfp->mfp; 01080 DB_MPOOL *dbmp = dbmfp->dbmp; 01081 DB_FH *fhp = &dbmfp->fh; 01082 CMPR cmpr; 01083 size_t count; 01084 01085 R_LOCK(dbenv, dbmp->reginfo); 01086 01087 cmpr.flags = DB_CMPR_FREE; 01088 cmpr.next = mfp->cmpr_free; 01089 mfp->cmpr_free = pgno; 01090 01091 #ifdef DEBUG_CMPR 01092 fprintf(stderr,"CDB___memp_cmpr_free:: freeing page:%3d \n",pgno); 01093 #endif 01094 01095 if((ret = CDB___os_seek(dbenv, fhp, pagesize, pgno, 0, 0, DB_OS_SEEK_SET)) != 0) { 01096 CDB___db_err(dbenv, "CDB___memp_cmpr_free: seek error at %d", pgno); 01097 ret = CDB___db_panic(dbenv, ret); 01098 goto err; 01099 } 01100 if((ret = CDB___os_write(dbenv, fhp, (void*)&cmpr, sizeof(CMPR), &count)) < 0) { 01101 CDB___db_err(dbenv, "CDB___memp_cmpr_free: write error at %d", pgno); 01102 ret = CDB___db_panic(dbenv, ret); 01103 goto err; 01104 } 01105 if(count != sizeof(CMPR)) { 01106 CDB___db_err(dbenv, "CDB___memp_cmpr_free: write error %d bytes instead of %d bytes", count, sizeof(CMPR)); 01107 ret = CDB___db_panic(dbenv, ret); 01108 goto err; 01109 } 01110 01111 err: 01112 R_UNLOCK(dbenv, dbmp->reginfo); 01113 return ret; 01114 } 01115 01116 01117 /* 01118 * CDB___memp_cmpr_alloc_chain -- 01119 * Allocate chain entry in BH 01120 * 01121 * PUBLIC: int CDB___memp_cmpr_alloc_chain __P((DB_MPOOL *, BH *)); 01122 */ 01123 01124 int 01125 CDB___memp_cmpr_alloc_chain(dbmp, bhp, alloc_type) 01126 DB_MPOOL *dbmp; 01127 BH *bhp; 01128 int alloc_type; 01129 { 01130 DB_ENV *dbenv = dbmp->dbenv; 01131 int ret = 0; 01132 if(!bhp->chain) { 01133 int alloc_ret; 01134 int alloc_length = sizeof(db_pgno_t)*(CMPR_MAX-1); 01135 switch(alloc_type) { 01136 case BH_CMPR_POOL: 01137 { 01138 MPOOL *mp = dbmp->reginfo[0].primary; 01139 int n_cache = NCACHE(mp, bhp->pgno); 01140 alloc_ret = CDB___memp_alloc(dbmp, &dbmp->reginfo[n_cache], NULL, alloc_length, NULL, (void *)(&bhp->chain)); 01141 F_SET(bhp, BH_CMPR_POOL); 01142 } 01143 break; 01144 case BH_CMPR_OS: 01145 alloc_ret = CDB___os_malloc(dbenv, alloc_length, NULL, &bhp->chain); 01146 F_SET(bhp, BH_CMPR_OS); 01147 break; 01148 default: 01149 CDB___db_err(dbenv, "CDB___memp_cmpr_alloc_chain: unknown alloc type :%d", alloc_type); 01150 ret = CDB___db_panic(dbenv, EINVAL); 01151 goto err; 01152 break; 01153 } 01154 01155 if(alloc_ret) { 01156 CDB___db_err(dbenv, "CDB___memp_cmpr_alloc_chain: memp_alloc %d bytes failed:%d", alloc_length, alloc_ret); 01157 ret = CDB___db_panic(dbenv, EINVAL); 01158 goto err; 01159 } 01160 memset((void *)bhp->chain, 0, alloc_length); 01161 #if defined(DEBUG_CMPR) || defined(DEBUG_CMPR_ALLOC) 01162 fprintf(stderr, "CDB___memp_cmpr_alloc_chain:: allocate chain in %s :%8x\n", (alloc_type == BH_CMPR_OS ? "malloc" : "shalloc"), bhp->chain); 01163 #endif 01164 } else { 01165 #ifdef DEBUG_CMPR 01166 fprintf(stderr, "CDB___memp_cmpr_alloc_chain:: existing chain:%8x\n", bhp->chain); 01167 #endif 01168 } 01169 F_SET(bhp, BH_CMPR); 01170 err: 01171 return ret; 01172 } 01173 01174 /* 01175 * CDB___memp_cmpr_free_chain -- 01176 * Free chain entry in BH 01177 * 01178 * PUBLIC: int CDB___memp_cmpr_free_chain __P((DB_MPOOL *, BH *)); 01179 */ 01180 01181 int 01182 CDB___memp_cmpr_free_chain(dbmp, bhp) 01183 DB_MPOOL *dbmp; 01184 BH *bhp; 01185 { 01186 DB_ENV *dbenv = dbmp->dbenv; 01187 01188 if(F_ISSET(bhp, BH_CMPR)) { 01189 if(bhp->chain) { 01190 int alloc_length = sizeof(db_pgno_t)*(CMPR_MAX-1); 01191 int alloc_type = bhp->flags & (BH_CMPR_POOL|BH_CMPR_OS); 01192 switch(alloc_type) { 01193 case BH_CMPR_POOL: 01194 { 01195 MPOOL *mp = dbmp->reginfo[0].primary; 01196 int n_cache = NCACHE(mp, bhp->pgno); 01197 CDB___db_shalloc_free(dbmp->reginfo[n_cache].addr, bhp->chain); 01198 } 01199 break; 01200 case BH_CMPR_OS: 01201 CDB___os_free(bhp->chain, alloc_length); 01202 break; 01203 default: 01204 CDB___db_err(dbenv, "CDB___memp_cmpr_free_chain: unknown alloc type :%d", alloc_type); 01205 return CDB___db_panic(dbenv, EINVAL); 01206 break; 01207 } 01208 #if defined(DEBUG_CMPR) || defined(DEBUG_CMPR_ALLOC) 01209 fprintf(stderr, "CDB___memp_cmpr_free_chain:: free chain in %s :%8x\n", (alloc_type == BH_CMPR_OS ? "malloc" : "shalloc"), bhp->chain); 01210 #endif 01211 bhp->chain = NULL; 01212 } else { 01213 CDB___db_err(dbenv, "CDB___memp_cmpr_free_chain: BH_CMPR set but null bhp->chain"); 01214 return CDB___db_panic(dbenv, EINVAL); 01215 } 01216 } else if(bhp->chain) { 01217 CDB___db_err(dbenv, "CDB___memp_cmpr_free_chain: BH_CMPR not set but bhp->chain not null"); 01218 return CDB___db_panic(dbenv, EINVAL); 01219 } 01220 01221 F_CLR(bhp, BH_CMPR | BH_CMPR_OS | BH_CMPR_POOL); 01222 01223 return 0; 01224 }