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