mp_cmpr.c

Go to the documentation of this file.
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 }

Generated on Sun Jun 8 10:56:38 2008 for GNUmifluz by  doxygen 1.5.5