db_method.c

Go to the documentation of this file.
00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1999, 2000
00005  *      Sleepycat Software.  All rights reserved.
00006  */
00007 
00008 #include "config.h"
00009 
00010 #ifndef lint
00011 static const char revid[] = "$Id: db__method_8c-source.html,v 1.1 2008/06/08 10:17:52 sebdiaz Exp $";
00012 #endif /* not lint */
00013 
00014 #ifndef NO_SYSTEM_INCLUDES
00015 #include <sys/types.h>
00016 
00017 #ifdef HAVE_RPC
00018 #include <rpc/rpc.h>
00019 #endif
00020 
00021 #include <errno.h>
00022 #include <string.h>
00023 #endif
00024 
00025 #ifdef HAVE_RPC
00026 #include "db_server.h"
00027 #endif
00028 
00029 #include "db_int.h"
00030 #include "db_page.h"
00031 #include "db_am.h"
00032 #include "btree.h"
00033 #include "hash.h"
00034 #include "qam.h"
00035 #include "xa.h"
00036 #include "xa_ext.h"
00037 
00038 #ifdef HAVE_RPC
00039 #include "gen_client_ext.h"
00040 #include "rpc_client_ext.h"
00041 #endif
00042 
00043 static int  __db_get_byteswapped __P((DB *));
00044 static DBTYPE
00045             __db_get_type __P((DB *));
00046 static int  __db_init __P((DB *, u_int32_t));
00047 static int  __db_key_range
00048                 __P((DB *, DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t));
00049 static int  __db_set_cachesize __P((DB *, u_int32_t, u_int32_t, int));
00050 static int  __db_set_dup_compare __P((DB *, int (*)(const DBT *, const DBT *)));
00051 static void __db_set_errcall __P((DB *, void (*)(const char *, char *)));
00052 static void __db_set_errfile __P((DB *, FILE *));
00053 static int  __db_set_feedback __P((DB *, void (*)(DB *, int, int)));
00054 static int  __db_set_flags __P((DB *, u_int32_t));
00055 static int  __db_set_lorder __P((DB *, int));
00056 static int  __db_set_malloc __P((DB *, void *(*)(size_t)));
00057 static int  __db_set_pagesize __P((DB *, u_int32_t));
00058 static int  __db_set_realloc __P((DB *, void *(*)(void *, size_t)));
00059 static void __db_set_errpfx __P((DB *, const char *));
00060 static int  __db_set_paniccall __P((DB *, void (*)(DB_ENV *, int)));
00061 static void __dbh_err __P((DB *, int, const char *, ...));
00062 static void __dbh_errx __P((DB *, const char *, ...));
00063 
00064 /*
00065  * CDB_db_create --
00066  *      DB constructor.
00067  */
00068 int
00069 CDB_db_create(dbpp, dbenv, flags)
00070         DB **dbpp;
00071         DB_ENV *dbenv;
00072         u_int32_t flags;
00073 {
00074         DB *dbp;
00075         int ret;
00076 
00077         /* Check for invalid function flags. */
00078         switch (flags) {
00079         case 0:
00080                 break;
00081         case DB_XA_CREATE:
00082                 if (dbenv != NULL) {
00083                         CDB___db_err(dbenv,
00084                 "XA applications may not specify an environment to CDB_db_create");
00085                         return (EINVAL);
00086                 }
00087 
00088                 /*
00089                  * If it's an XA database, open it within the XA environment,
00090                  * taken from the global list of environments.  (When the XA
00091                  * transaction manager called our xa_start() routine the
00092                  * "current" environment was moved to the start of the list.
00093                  */
00094                 dbenv = TAILQ_FIRST(&DB_GLOBAL(db_envq));
00095                 break;
00096         default:
00097                 return (CDB___db_ferr(dbenv, "CDB_db_create", 0));
00098         }
00099 
00100         /* Allocate the DB. */
00101         if ((ret = CDB___os_calloc(dbenv, 1, sizeof(*dbp), &dbp)) != 0)
00102                 return (ret);
00103 #ifdef HAVE_RPC
00104         if (dbenv != NULL && dbenv->cl_handle != NULL)
00105                 ret = __dbcl_init(dbp, dbenv, flags);
00106         else
00107 #endif
00108                 ret = __db_init(dbp, flags);
00109         if (ret != 0) {
00110                 CDB___os_free(dbp, sizeof(*dbp));
00111                 return (ret);
00112         }
00113 
00114         /* If we don't have an environment yet, allocate a local one. */
00115         if (dbenv == NULL) {
00116                 if ((ret = CDB_db_env_create(&dbenv, 0)) != 0) {
00117                         CDB___os_free(dbp, sizeof(*dbp));
00118                         return (ret);
00119                 }
00120                 dbenv->dblocal_ref = 0;
00121                 F_SET(dbenv, DB_ENV_DBLOCAL);
00122         }
00123         if (F_ISSET(dbenv, DB_ENV_DBLOCAL))
00124                 ++dbenv->dblocal_ref;
00125 
00126         dbp->dbenv = dbenv;
00127 
00128         *dbpp = dbp;
00129         return (0);
00130 }
00131 
00132 /*
00133  * __db_init --
00134  *      Initialize a DB structure.
00135  */
00136 static int
00137 __db_init(dbp, flags)
00138         DB *dbp;
00139         u_int32_t flags;
00140 {
00141         int ret;
00142 
00143         dbp->log_fileid = DB_LOGFILEID_INVALID;
00144 
00145         TAILQ_INIT(&dbp->free_queue);
00146         TAILQ_INIT(&dbp->active_queue);
00147         TAILQ_INIT(&dbp->join_queue);
00148 
00149         FLD_SET(dbp->am_ok,
00150             DB_OK_BTREE | DB_OK_HASH | DB_OK_QUEUE | DB_OK_RECNO);
00151 
00152         dbp->close = CDB___db_close;
00153         dbp->cursor = CDB___db_cursor;
00154         dbp->del = NULL;                /* !!! Must be set by access method. */
00155         dbp->err = __dbh_err;
00156         dbp->errx = __dbh_errx;
00157         dbp->fd = CDB___db_fd;
00158         dbp->get = CDB___db_get;
00159         dbp->get_byteswapped = __db_get_byteswapped;
00160         dbp->get_type = __db_get_type;
00161         dbp->join = CDB___db_join;
00162         dbp->key_range = __db_key_range;
00163         dbp->open = CDB___db_open;
00164         dbp->put = CDB___db_put;
00165         dbp->remove = CDB___db_remove;
00166         dbp->rename = CDB___db_rename;
00167         dbp->set_cachesize = __db_set_cachesize;
00168         dbp->set_dup_compare = __db_set_dup_compare;
00169         dbp->set_errcall = __db_set_errcall;
00170         dbp->set_errfile = __db_set_errfile;
00171         dbp->set_errpfx = __db_set_errpfx;
00172         dbp->set_feedback = __db_set_feedback;
00173         dbp->set_flags = __db_set_flags;
00174         dbp->set_lorder = __db_set_lorder;
00175         dbp->set_malloc = __db_set_malloc;
00176         dbp->set_pagesize = __db_set_pagesize;
00177         dbp->set_paniccall = __db_set_paniccall;
00178         dbp->set_realloc = __db_set_realloc;
00179         dbp->stat = NULL;               /* !!! Must be set by access method. */
00180         dbp->sync = CDB___db_sync;
00181         dbp->tags = 0;
00182         dbp->upgrade = CDB___db_upgrade;
00183         dbp->verify = CDB___db_verify;
00184                                         /* Access method specific. */
00185         if ((ret = CDB___bam_db_create(dbp)) != 0)
00186                 return (ret);
00187         if ((ret = CDB___ham_db_create(dbp)) != 0)
00188                 return (ret);
00189         if ((ret = CDB___qam_db_create(dbp)) != 0)
00190                 return (ret);
00191 
00192         /*
00193          * XA specific: must be last, as we replace methods set by the
00194          * access methods.
00195          */
00196         if (LF_ISSET(DB_XA_CREATE) && (ret = CDB___db_xa_create(dbp)) != 0)
00197                 return (ret);
00198 
00199         return (0);
00200 }
00201 
00202 /*
00203  * CDB___dbh_am_chk --
00204  *      Error if an unreasonable method is called.
00205  *
00206  * PUBLIC: int CDB___dbh_am_chk __P((DB *, u_int32_t));
00207  */
00208 int
00209 CDB___dbh_am_chk(dbp, flags)
00210         DB *dbp;
00211         u_int32_t flags;
00212 {
00213         /*
00214          * We start out allowing any access methods to be called, and as the
00215          * application calls the methods the options become restricted.  The
00216          * idea is to quit as soon as an illegal method combination is called.
00217          */
00218         if ((LF_ISSET(DB_OK_BTREE) && FLD_ISSET(dbp->am_ok, DB_OK_BTREE)) ||
00219             (LF_ISSET(DB_OK_HASH) && FLD_ISSET(dbp->am_ok, DB_OK_HASH)) ||
00220             (LF_ISSET(DB_OK_QUEUE) && FLD_ISSET(dbp->am_ok, DB_OK_QUEUE)) ||
00221             (LF_ISSET(DB_OK_RECNO) && FLD_ISSET(dbp->am_ok, DB_OK_RECNO))) {
00222                 FLD_CLR(dbp->am_ok, ~flags);
00223                 return (0);
00224         }
00225 
00226         CDB___db_err(dbp->dbenv,
00227     "call implies an access method which is inconsistent with previous calls");
00228         return (EINVAL);
00229 }
00230 
00231 /*
00232  * __dbh_err --
00233  *      Error message, including the standard error string.
00234  */
00235 static void
00236 #ifdef __STDC__
00237 __dbh_err(DB *dbp, int error, const char *fmt, ...)
00238 #else
00239 __dbh_err(dbp, error, fmt, va_alist)
00240         DB *dbp;
00241         int error;
00242         const char *fmt;
00243         va_dcl
00244 #endif
00245 {
00246         va_list ap;
00247 
00248 #ifdef __STDC__
00249         va_start(ap, fmt);
00250 #else
00251         va_start(ap);
00252 #endif
00253         CDB___db_real_err(dbp->dbenv, error, 1, 1, fmt, ap);
00254 
00255         va_end(ap);
00256 }
00257 
00258 /*
00259  * __dbh_errx --
00260  *      Error message.
00261  */
00262 static void
00263 #ifdef __STDC__
00264 __dbh_errx(DB *dbp, const char *fmt, ...)
00265 #else
00266 __dbh_errx(dbp, fmt, va_alist)
00267         DB *dbp;
00268         const char *fmt;
00269         va_dcl
00270 #endif
00271 {
00272         va_list ap;
00273 
00274 #ifdef __STDC__
00275         va_start(ap, fmt);
00276 #else
00277         va_start(ap);
00278 #endif
00279         CDB___db_real_err(dbp->dbenv, 0, 0, 1, fmt, ap);
00280 
00281         va_end(ap);
00282 }
00283 
00284 /*
00285  * __db_get_byteswapped --
00286  *      Return if database requires byte swapping.
00287  */
00288 static int
00289 __db_get_byteswapped(dbp)
00290         DB *dbp;
00291 {
00292         DB_ILLEGAL_BEFORE_OPEN(dbp, "get_byteswapped");
00293 
00294         return (F_ISSET(dbp, DB_AM_SWAP) ? 1 : 0);
00295 }
00296 
00297 /*
00298  * __db_get_type --
00299  *      Return type of underlying database.
00300  */
00301 static DBTYPE
00302 __db_get_type(dbp)
00303         DB *dbp;
00304 {
00305         DB_ILLEGAL_BEFORE_OPEN(dbp, "get_type");
00306 
00307         return (dbp->type);
00308 }
00309 
00310 /*
00311  * __db_key_range --
00312  *      Return proportion of keys above and below given key.
00313  */
00314 static int
00315 __db_key_range(dbp, txn, key, kr, flags)
00316         DB *dbp;
00317         DB_TXN *txn;
00318         DBT *key;
00319         DB_KEY_RANGE *kr;
00320         u_int32_t flags;
00321 {
00322         COMPQUIET(txn, NULL);
00323         COMPQUIET(key, NULL);
00324         COMPQUIET(kr, NULL);
00325         COMPQUIET(flags, 0);
00326 
00327         DB_ILLEGAL_BEFORE_OPEN(dbp, "key_range");
00328         DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
00329 
00330         return (EINVAL);
00331 }
00332 
00333 /*
00334  * __db_set_cachesize --
00335  *      Set underlying cache size.
00336  */
00337 static int
00338 __db_set_cachesize(dbp, cache_gbytes, cache_bytes, ncache)
00339         DB *dbp;
00340         u_int32_t cache_gbytes, cache_bytes;
00341         int ncache;
00342 {
00343         DB_ILLEGAL_IN_ENV(dbp, "set_cachesize");
00344         DB_ILLEGAL_AFTER_OPEN(dbp, "set_cachesize");
00345 
00346         return (dbp->dbenv->set_cachesize(
00347             dbp->dbenv, cache_gbytes, cache_bytes, ncache));
00348 }
00349 
00350 /*
00351  * __db_set_dup_compare --
00352  *      Set duplicate comparison routine.
00353  */
00354 static int
00355 __db_set_dup_compare(dbp, func)
00356         DB *dbp;
00357         int (*func) __P((const DBT *, const DBT *));
00358 {
00359         DB_ILLEGAL_AFTER_OPEN(dbp, "dup_compare");
00360         DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE | DB_OK_HASH);
00361 
00362         dbp->dup_compare = func;
00363 
00364         return (0);
00365 }
00366 
00367 static void
00368 __db_set_errcall(dbp, errcall)
00369         DB *dbp;
00370         void (*errcall) __P((const char *, char *));
00371 {
00372         dbp->dbenv->set_errcall(dbp->dbenv, errcall);
00373 }
00374 
00375 static void
00376 __db_set_errfile(dbp, errfile)
00377         DB *dbp;
00378         FILE *errfile;
00379 {
00380         dbp->dbenv->set_errfile(dbp->dbenv, errfile);
00381 }
00382 
00383 static void
00384 __db_set_errpfx(dbp, errpfx)
00385         DB *dbp;
00386         const char *errpfx;
00387 {
00388         dbp->dbenv->set_errpfx(dbp->dbenv, errpfx);
00389 }
00390 
00391 static int
00392 __db_set_feedback(dbp, feedback)
00393         DB *dbp;
00394         void (*feedback) __P((DB *, int, int));
00395 {
00396         dbp->db_feedback = feedback;
00397         return (0);
00398 }
00399 
00400 static int
00401 __db_set_flags(dbp, flags)
00402         DB *dbp;
00403         u_int32_t flags;
00404 {
00405         int ret;
00406 
00407         /*
00408          * !!!
00409          * The hash access method only takes two flags: DB_DUP and DB_DUPSORT.
00410          * The Btree access method uses them for the same purposes, and so we
00411          * resolve them there.
00412          *
00413          * The queue access method takes no flags.
00414          */
00415         if ((ret = CDB___bam_set_flags(dbp, &flags)) != 0)
00416                 return (ret);
00417         if ((ret = CDB___ram_set_flags(dbp, &flags)) != 0)
00418                 return (ret);
00419 
00420         return (flags == 0 ? 0 : CDB___db_ferr(dbp->dbenv, "DB->set_flags", 0));
00421 }
00422 
00423 static int
00424 __db_set_lorder(dbp, db_lorder)
00425         DB *dbp;
00426         int db_lorder;
00427 {
00428         int ret;
00429 
00430         DB_ILLEGAL_AFTER_OPEN(dbp, "set_lorder");
00431 
00432         /* Flag if the specified byte order requires swapping. */
00433         switch (ret = CDB___db_byteorder(dbp->dbenv, db_lorder)) {
00434         case 0:
00435                 F_CLR(dbp, DB_AM_SWAP);
00436                 break;
00437         case DB_SWAPBYTES:
00438                 F_SET(dbp, DB_AM_SWAP);
00439                 break;
00440         default:
00441                 return (ret);
00442                 /* NOTREACHED */
00443         }
00444         return (0);
00445 }
00446 
00447 static int
00448 __db_set_malloc(dbp, func)
00449         DB *dbp;
00450         void *(*func) __P((size_t));
00451 {
00452         DB_ILLEGAL_AFTER_OPEN(dbp, "set_malloc");
00453 
00454         dbp->db_malloc = func;
00455         return (0);
00456 }
00457 
00458 static int
00459 __db_set_pagesize(dbp, db_pagesize)
00460         DB *dbp;
00461         u_int32_t db_pagesize;
00462 {
00463         DB_ILLEGAL_AFTER_OPEN(dbp, "set_pagesize");
00464 
00465         if (db_pagesize < DB_MIN_PGSIZE) {
00466                 CDB___db_err(dbp->dbenv, "page sizes may not be smaller than %lu",
00467                     (u_long)DB_MIN_PGSIZE);
00468                 return (EINVAL);
00469         }
00470         if (db_pagesize > DB_MAX_PGSIZE) {
00471                 CDB___db_err(dbp->dbenv, "page sizes may not be larger than %lu",
00472                     (u_long)DB_MAX_PGSIZE);
00473                 return (EINVAL);
00474         }
00475 
00476         /*
00477          * We don't want anything that's not a power-of-2, as we rely on that
00478          * for alignment of various types on the pages.
00479          */
00480         if ((u_int32_t)1 << CDB___db_log2(db_pagesize) != db_pagesize) {
00481                 CDB___db_err(dbp->dbenv, "page sizes must be a power-of-2");
00482                 return (EINVAL);
00483         }
00484 
00485         /*
00486          * XXX
00487          * Should we be checking for a page size that's not a multiple of 512,
00488          * so that we never try and write less than a disk sector?
00489          */
00490         dbp->pgsize = db_pagesize;
00491 
00492         return (0);
00493 }
00494 
00495 static int
00496 __db_set_realloc(dbp, func)
00497         DB *dbp;
00498         void *(*func) __P((void *, size_t));
00499 {
00500         DB_ILLEGAL_AFTER_OPEN(dbp, "set_realloc");
00501 
00502         dbp->db_realloc = func;
00503         return (0);
00504 }
00505 
00506 static int
00507 __db_set_paniccall(dbp, paniccall)
00508         DB *dbp;
00509         void (*paniccall) __P((DB_ENV *, int));
00510 {
00511         return (dbp->dbenv->set_paniccall(dbp->dbenv, paniccall));
00512 }
00513 
00514 #ifdef HAVE_RPC
00515 /*
00516  * __dbcl_init --
00517  *      Initialize a DB structure on the server.
00518  *
00519  * PUBLIC: #ifdef HAVE_RPC
00520  * PUBLIC: int __dbcl_init __P((DB *, DB_ENV *, u_int32_t));
00521  * PUBLIC: #endif
00522  */
00523 int
00524 __dbcl_init(dbp, dbenv, flags)
00525         DB *dbp;
00526         DB_ENV *dbenv;
00527         u_int32_t flags;
00528 {
00529         CLIENT *cl;
00530         __db_create_reply *replyp;
00531         __db_create_msg req;
00532         int ret;
00533 
00534         TAILQ_INIT(&dbp->free_queue);
00535         TAILQ_INIT(&dbp->active_queue);
00536 
00537         dbp->close = __dbcl_db_close;
00538         dbp->cursor = __dbcl_db_cursor;
00539         dbp->del = __dbcl_db_del;
00540         dbp->err = __dbh_err;
00541         dbp->errx = __dbh_errx;
00542         dbp->fd = __dbcl_db_fd;
00543         dbp->get = __dbcl_db_get;
00544         dbp->get_byteswapped = __dbcl_db_swapped;
00545         dbp->get_type = __db_get_type;
00546         dbp->join = __dbcl_db_join;
00547         dbp->key_range = __dbcl_db_key_range;
00548         dbp->open = __dbcl_db_open;
00549         dbp->put = __dbcl_db_put;
00550         dbp->remove = __dbcl_db_remove;
00551         dbp->rename = __dbcl_db_rename;
00552         dbp->set_cachesize = __dbcl_db_cachesize;
00553         dbp->set_dup_compare = NULL;
00554         dbp->set_errcall = __db_set_errcall;
00555         dbp->set_errfile = __db_set_errfile;
00556         dbp->set_errpfx = __db_set_errpfx;
00557         dbp->set_feedback = __dbcl_db_feedback;
00558         dbp->set_flags = __dbcl_db_flags;
00559         dbp->set_lorder = __dbcl_db_lorder;
00560         dbp->set_malloc = __dbcl_db_malloc;
00561         dbp->set_pagesize = __dbcl_db_pagesize;
00562         dbp->set_paniccall = __dbcl_db_panic;
00563         dbp->set_realloc = __dbcl_db_realloc;
00564         dbp->stat = __dbcl_db_stat;
00565         dbp->sync = __dbcl_db_sync;
00566         dbp->upgrade = __dbcl_db_upgrade;
00567 
00568         /*
00569          * Set all the method specific functions to client funcs as well.
00570          */
00571         dbp->set_bt_compare = __dbcl_db_bt_compare;
00572         dbp->set_bt_maxkey = __dbcl_db_bt_maxkey;
00573         dbp->set_bt_minkey = __dbcl_db_bt_minkey;
00574         dbp->set_bt_prefix = __dbcl_db_bt_prefix;
00575         dbp->set_h_ffactor = __dbcl_db_h_ffactor;
00576         dbp->set_h_hash = __dbcl_db_h_hash;
00577         dbp->set_h_nelem = __dbcl_db_h_nelem;
00578         dbp->set_re_delim = __dbcl_db_re_delim;
00579         dbp->set_re_len = __dbcl_db_re_len;
00580         dbp->set_re_pad = __dbcl_db_re_pad;
00581         dbp->set_re_source = __dbcl_db_re_source;
00582 
00583         cl = (CLIENT *)dbenv->cl_handle;
00584         req.flags = flags;
00585         req.envpcl_id = dbenv->cl_id;
00586 
00587         /*
00588          * CALL THE SERVER
00589          */
00590         replyp = __db_db_create_1(&req, cl);
00591         if (replyp == NULL) {
00592                 CDB___db_err(dbenv, clnt_sperror(cl, "Berkeley DB"));
00593                 return (DB_NOSERVER);
00594         }
00595 
00596         if ((ret = replyp->status) != 0)
00597                 return (ret);
00598 
00599         dbp->cl_id = replyp->dbpcl_id;
00600         return (0);
00601 }
00602 #endif

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