00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef _DB_INTERNAL_H_
00012 #define _DB_INTERNAL_H_
00013
00014
00015
00016
00017
00018 #ifndef NO_SYSTEM_INCLUDES
00019 #if defined(STDC_HEADERS) || defined(__cplusplus)
00020 #include <stdarg.h>
00021 #else
00022 #include <varargs.h>
00023 #endif
00024 #include <errno.h>
00025 #endif
00026
00027 #include "db.h"
00028
00029 #include "dbinc/queue.h"
00030 #include "dbinc/shqueue.h"
00031
00032 #if defined(__cplusplus)
00033 extern "C" {
00034 #endif
00035
00036
00037
00038
00039 #ifndef UINT16_MAX
00040 #define UINT16_MAX 65535
00041 #endif
00042 #ifndef UINT32_MAX
00043 #ifdef __STDC__
00044 #define UINT32_MAX 4294967295U
00045 #else
00046 #define UINT32_MAX 0xffffffff
00047 #endif
00048 #endif
00049
00050 #if defined(HAVE_64BIT_TYPES)
00051 #undef INT64_MAX
00052 #undef INT64_MIN
00053 #undef UINT64_MAX
00054
00055 #ifdef DB_WIN32
00056 #define INT64_MAX _I64_MAX
00057 #define INT64_MIN _I64_MIN
00058 #define UINT64_MAX _UI64_MAX
00059
00060 #define INT64_FMT "%l64d"
00061 #define UINT64_FMT "%l64u"
00062 #else
00063
00064
00065
00066
00067
00068 #define INT64_MAX 9223372036854775807LL
00069 #define INT64_MIN (-INT64_MAX-1)
00070 #define UINT64_MAX 18446744073709551615ULL
00071
00072
00073
00074 #endif
00075 #endif
00076
00077 #define MEGABYTE 1048576
00078 #define GIGABYTE 1073741824
00079
00080 #define MS_PER_SEC 1000
00081 #define USEC_PER_MS 1000
00082
00083 #define RECNO_OOB 0
00084
00085
00086 #define POWER_OF_TWO(x) (((x) & ((x) - 1)) == 0)
00087
00088
00089 #define DB_MIN_PGSIZE 0x000200
00090 #define DB_MAX_PGSIZE 0x010000
00091 #define IS_VALID_PAGESIZE(x) \
00092 (POWER_OF_TWO(x) && (x) >= DB_MIN_PGSIZE && ((x) <= DB_MAX_PGSIZE))
00093
00094
00095 #define DB_MINPAGECACHE 16
00096
00097
00098
00099
00100
00101 #define DB_DEF_IOSIZE (8 * 1024)
00102
00103
00104 #undef DB_ALIGN
00105 #define DB_ALIGN(v, bound) \
00106 (((v) + (bound) - 1) & ~(((uintmax_t)(bound)) - 1))
00107
00108
00109 #undef ALIGNP_INC
00110 #define ALIGNP_INC(p, bound) \
00111 (void *)(((uintptr_t)(p) + (bound) - 1) & ~(((uintptr_t)(bound)) - 1))
00112
00113
00114 #undef ALIGNP_DEC
00115 #define ALIGNP_DEC(p, bound) \
00116 (void *)((uintptr_t)(p) & ~(((uintptr_t)(bound)) - 1))
00117
00118
00119
00120
00121
00122
00123 #define P_TO_ULONG(p) ((u_long)(uintptr_t)(p))
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133 #define P_TO_UINT32(p) ((u_int32_t)(uintptr_t)(p))
00134 #define P_TO_UINT16(p) ((u_int16_t)(uintptr_t)(p))
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149 #undef SSZ
00150 #define SSZ(name, field) P_TO_UINT16(&(((name *)0)->field))
00151
00152 #undef SSZA
00153 #define SSZA(name, field) P_TO_UINT16(&(((name *)0)->field[0]))
00154
00155
00156 typedef struct __fn {
00157 u_int32_t mask;
00158 const char *name;
00159 } FN;
00160
00161
00162 #define FLD_CLR(fld, f) (fld) &= ~(f)
00163 #define FLD_ISSET(fld, f) ((fld) & (f))
00164 #define FLD_SET(fld, f) (fld) |= (f)
00165 #define F_CLR(p, f) (p)->flags &= ~(f)
00166 #define F_ISSET(p, f) ((p)->flags & (f))
00167 #define F_SET(p, f) (p)->flags |= (f)
00168 #define LF_CLR(f) ((flags) &= ~(f))
00169 #define LF_ISSET(f) ((flags) & (f))
00170 #define LF_SET(f) ((flags) |= (f))
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 #define DB_PCT(v, total) \
00181 ((int)((total) == 0 ? 0 : ((double)(v) * 100) / (total)))
00182 #define DB_PCT_PG(v, total, pgsize) \
00183 ((int)((total) == 0 ? 0 : \
00184 100 - ((double)(v) * 100) / (((double)total) * (pgsize))))
00185
00186
00187
00188
00189
00190
00191 typedef struct __db_msgbuf {
00192 char *buf;
00193 char *cur;
00194 size_t len;
00195 } DB_MSGBUF;
00196 #define DB_MSGBUF_INIT(a) do { \
00197 (a)->buf = (a)->cur = NULL; \
00198 (a)->len = 0; \
00199 } while (0)
00200 #define DB_MSGBUF_FLUSH(dbenv, a) do { \
00201 if ((a)->buf != NULL) { \
00202 if ((a)->cur != (a)->buf) \
00203 __db_msg(dbenv, "%s", (a)->buf); \
00204 __os_free(dbenv, (a)->buf); \
00205 DB_MSGBUF_INIT(a); \
00206 } \
00207 } while (0)
00208 #define STAT_FMT(msg, fmt, type, v) do { \
00209 DB_MSGBUF __mb; \
00210 DB_MSGBUF_INIT(&__mb); \
00211 __db_msgadd(dbenv, &__mb, fmt, (type)(v)); \
00212 __db_msgadd(dbenv, &__mb, "\t%s", msg); \
00213 DB_MSGBUF_FLUSH(dbenv, &__mb); \
00214 } while (0)
00215 #define STAT_HEX(msg, v) \
00216 __db_msg(dbenv, "%#lx\t%s", (u_long)(v), msg)
00217 #define STAT_ISSET(msg, p) \
00218 __db_msg(dbenv, "%sSet\t%s", (p) == NULL ? "!" : " ", msg)
00219 #define STAT_LONG(msg, v) \
00220 __db_msg(dbenv, "%ld\t%s", (long)(v), msg)
00221 #define STAT_LSN(msg, lsnp) \
00222 __db_msg(dbenv, "%lu/%lu\t%s", \
00223 (u_long)(lsnp)->file, (u_long)(lsnp)->offset, msg)
00224 #define STAT_POINTER(msg, v) \
00225 __db_msg(dbenv, "%#lx\t%s", P_TO_ULONG(v), msg)
00226 #define STAT_STRING(msg, p) do { \
00227 const char *__p = p; \
00228 __db_msg(dbenv, "%s\t%s", __p == NULL ? "!Set" : __p, msg); \
00229 } while (0)
00230 #define STAT_ULONG(msg, v) \
00231 __db_msg(dbenv, "%lu\t%s", (u_long)(v), msg)
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241 #define DB_RETOK_STD(ret) ((ret) == 0)
00242 #define DB_RETOK_DBCDEL(ret) ((ret) == 0 || (ret) == DB_KEYEMPTY || \
00243 (ret) == DB_NOTFOUND)
00244 #define DB_RETOK_DBCGET(ret) ((ret) == 0 || (ret) == DB_KEYEMPTY || \
00245 (ret) == DB_NOTFOUND)
00246 #define DB_RETOK_DBCPUT(ret) ((ret) == 0 || (ret) == DB_KEYEXIST || \
00247 (ret) == DB_NOTFOUND)
00248 #define DB_RETOK_DBDEL(ret) DB_RETOK_DBCDEL(ret)
00249 #define DB_RETOK_DBGET(ret) DB_RETOK_DBCGET(ret)
00250 #define DB_RETOK_DBPUT(ret) ((ret) == 0 || (ret) == DB_KEYEXIST)
00251 #define DB_RETOK_LGGET(ret) ((ret) == 0 || (ret) == DB_NOTFOUND)
00252 #define DB_RETOK_MPGET(ret) ((ret) == 0 || (ret) == DB_PAGE_NOTFOUND)
00253 #define DB_RETOK_REPPMSG(ret) ((ret) == 0 || \
00254 (ret) == DB_REP_IGNORE || \
00255 (ret) == DB_REP_ISPERM || \
00256 (ret) == DB_REP_NEWMASTER || \
00257 (ret) == DB_REP_NEWSITE || \
00258 (ret) == DB_REP_NOTPERM || \
00259 (ret) == DB_REP_STARTUPDONE)
00260
00261
00262 #ifdef EOPNOTSUPP
00263 #define DB_OPNOTSUP EOPNOTSUPP
00264 #else
00265 #ifdef ENOTSUP
00266 #define DB_OPNOTSUP ENOTSUP
00267 #else
00268 #define DB_OPNOTSUP EINVAL
00269 #endif
00270 #endif
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280 #undef MAXPATHLEN
00281 #define MAXPATHLEN 1024
00282
00283 #define PATH_DOT "."
00284
00285 #define PATH_SEPARATOR "\\/:"
00286
00287
00288
00289
00290
00291 typedef enum {
00292 DB_APP_NONE=0,
00293 DB_APP_DATA,
00294 DB_APP_LOG,
00295 DB_APP_TMP
00296 } APPNAME;
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310 #define ALIVE_ON(dbenv) ((dbenv)->is_alive != NULL)
00311 #define CDB_LOCKING(dbenv) F_ISSET(dbenv, DB_ENV_CDB)
00312 #define CRYPTO_ON(dbenv) ((dbenv)->crypto_handle != NULL)
00313 #define LOCKING_ON(dbenv) ((dbenv)->lk_handle != NULL)
00314 #define LOGGING_ON(dbenv) ((dbenv)->lg_handle != NULL)
00315 #define MPOOL_ON(dbenv) ((dbenv)->mp_handle != NULL)
00316 #define MUTEX_ON(dbenv) ((dbenv)->mutex_handle != NULL)
00317 #define REP_ON(dbenv) ((dbenv)->rep_handle != NULL)
00318 #define RPC_ON(dbenv) ((dbenv)->cl_handle != NULL)
00319 #define TXN_ON(dbenv) ((dbenv)->tx_handle != NULL)
00320
00321
00322
00323
00324
00325
00326 #define STD_LOCKING(dbc) \
00327 (!F_ISSET(dbc, DBC_OPD) && \
00328 !CDB_LOCKING((dbc)->dbp->dbenv) && LOCKING_ON((dbc)->dbp->dbenv))
00329
00330
00331
00332
00333 #define IS_RECOVERING(dbenv) \
00334 (LOGGING_ON(dbenv) && \
00335 F_ISSET((DB_LOG *)(dbenv)->lg_handle, DBLOG_RECOVER))
00336
00337
00338 #define ENV_ILLEGAL_AFTER_OPEN(dbenv, name) \
00339 if (F_ISSET((dbenv), DB_ENV_OPEN_CALLED)) \
00340 return (__db_mi_open(dbenv, name, 1));
00341 #define ENV_ILLEGAL_BEFORE_OPEN(dbenv, name) \
00342 if (!F_ISSET((dbenv), DB_ENV_OPEN_CALLED)) \
00343 return (__db_mi_open(dbenv, name, 0));
00344
00345
00346 #define ENV_REQUIRES_CONFIG(dbenv, handle, i, flags) \
00347 if (handle == NULL) \
00348 return (__db_env_config(dbenv, i, flags));
00349 #define ENV_NOT_CONFIGURED(dbenv, handle, i, flags) \
00350 if (F_ISSET((dbenv), DB_ENV_OPEN_CALLED)) \
00351 ENV_REQUIRES_CONFIG(dbenv, handle, i, flags)
00352
00353 #define ENV_ENTER(dbenv, ip) do { \
00354 int __ret; \
00355 if ((dbenv)->thr_hashtab == NULL) \
00356 ip = NULL; \
00357 else { \
00358 if ((__ret = \
00359 __env_set_state(dbenv, &(ip), THREAD_ACTIVE)) != 0) \
00360 return (__ret); \
00361 } \
00362 } while (0)
00363
00364 #ifdef DIAGNOSTIC
00365 #define ENV_LEAVE(dbenv, ip) do { \
00366 if ((ip) != NULL) { \
00367 DB_ASSERT(ip->dbth_state == THREAD_ACTIVE); \
00368 (ip)->dbth_state = THREAD_OUT; \
00369 } \
00370 } while (0)
00371 #else
00372 #define ENV_LEAVE(dbenv, ip) do { \
00373 if ((ip) != NULL) \
00374 (ip)->dbth_state = THREAD_OUT; \
00375 } while (0)
00376 #endif
00377 #ifdef DIAGNOSTIC
00378 #define CHECK_THREAD(dbenv) do { \
00379 DB_THREAD_INFO *__ip; \
00380 if ((dbenv)->thr_hashtab != NULL) { \
00381 (void)__env_set_state(dbenv, &__ip, THREAD_DIAGNOSTIC); \
00382 DB_ASSERT(__ip != NULL && \
00383 __ip->dbth_state != THREAD_OUT); \
00384 } \
00385 } while (0)
00386 #define CHECK_MTX_THREAD(dbenv, mtx) do { \
00387 if (mtx->alloc_id != MTX_MUTEX_REGION && \
00388 mtx->alloc_id != MTX_ENV_REGION && \
00389 mtx->alloc_id != MTX_APPLICATION) \
00390 CHECK_THREAD(dbenv); \
00391 } while (0)
00392 #else
00393 #define CHECK_THREAD(dbenv)
00394 #define CHECK_MTX_THREAD(dbenv, mtx)
00395 #endif
00396
00397 typedef enum {
00398 THREAD_SLOT_NOT_IN_USE=0,
00399 THREAD_OUT,
00400 THREAD_ACTIVE,
00401 THREAD_BLOCKED
00402 #ifdef DIAGNOSTIC
00403 , THREAD_DIAGNOSTIC
00404 #endif
00405 } DB_THREAD_STATE;
00406
00407 typedef struct __db_thread_info {
00408 pid_t dbth_pid;
00409 db_threadid_t dbth_tid;
00410 DB_THREAD_STATE dbth_state;
00411 SH_TAILQ_ENTRY dbth_links;
00412 } DB_THREAD_INFO;
00413
00414 typedef struct __env_thread_info {
00415 u_int32_t thr_count;
00416 u_int32_t thr_max;
00417 u_int32_t thr_nbucket;
00418 roff_t thr_hashoff;
00419 } THREAD_INFO;
00420
00421
00422
00423
00424
00425
00426
00427
00428 #define DB_IS_THREADED(dbp) \
00429 ((dbp)->mutex != MUTEX_INVALID)
00430
00431
00432 #define DB_ILLEGAL_AFTER_OPEN(dbp, name) \
00433 if (F_ISSET((dbp), DB_AM_OPEN_CALLED)) \
00434 return (__db_mi_open((dbp)->dbenv, name, 1));
00435 #define DB_ILLEGAL_BEFORE_OPEN(dbp, name) \
00436 if (!F_ISSET((dbp), DB_AM_OPEN_CALLED)) \
00437 return (__db_mi_open((dbp)->dbenv, name, 0));
00438
00439 #define DB_ILLEGAL_IN_ENV(dbp, name) \
00440 if (!F_ISSET((dbp)->dbenv, DB_ENV_DBLOCAL)) \
00441 return (__db_mi_env((dbp)->dbenv, name));
00442 #define DB_ILLEGAL_METHOD(dbp, flags) { \
00443 int __ret; \
00444 if ((__ret = __dbh_am_chk(dbp, flags)) != 0) \
00445 return (__ret); \
00446 }
00447
00448
00449
00450
00451
00452 #define __DBC_INTERNAL \
00453 DBC *opd; \
00454 \
00455 void *page; \
00456 db_pgno_t root; \
00457 db_pgno_t pgno; \
00458 db_indx_t indx; \
00459 \
00460 DB_LOCK lock; \
00461 db_lockmode_t lock_mode;
00462
00463 struct __dbc_internal {
00464 __DBC_INTERNAL
00465 };
00466
00467
00468 typedef enum { MU_REMOVE, MU_RENAME, MU_OPEN } mu_action;
00469
00470
00471
00472
00473
00474 #define IS_INITIALIZED(dbc) ((dbc)->internal->pgno != PGNO_INVALID)
00475
00476
00477 #define FREE_IF_NEEDED(sdbp, dbt) \
00478 if (F_ISSET((dbt), DB_DBT_APPMALLOC)) { \
00479 __os_ufree((sdbp)->dbenv, (dbt)->data); \
00480 F_CLR((dbt), DB_DBT_APPMALLOC); \
00481 }
00482
00483
00484
00485
00486
00487 #define SET_RET_MEM(dbc, owner) \
00488 do { \
00489 (dbc)->rskey = &(owner)->my_rskey; \
00490 (dbc)->rkey = &(owner)->my_rkey; \
00491 (dbc)->rdata = &(owner)->my_rdata; \
00492 } while (0)
00493
00494
00495 #define COPY_RET_MEM(src, dest) \
00496 do { \
00497 (dest)->rskey = (src)->rskey; \
00498 (dest)->rkey = (src)->rkey; \
00499 (dest)->rdata = (src)->rdata; \
00500 } while (0)
00501
00502
00503 #define RESET_RET_MEM(dbc) \
00504 do { \
00505 (dbc)->rskey = &(dbc)->my_rskey; \
00506 (dbc)->rkey = &(dbc)->my_rkey; \
00507 (dbc)->rdata = &(dbc)->my_rdata; \
00508 } while (0)
00509
00510
00511
00512
00513
00514
00515
00516 #define DB_FTYPE_SET -1
00517 #define DB_FTYPE_NOTSET 0
00518 #define DB_LSN_OFF_NOTSET -1
00519 #define DB_CLEARLEN_NOTSET UINT32_MAX
00520
00521
00522 typedef struct __dbpginfo {
00523 size_t db_pagesize;
00524 u_int32_t flags;
00525 DBTYPE type;
00526 } DB_PGINFO;
00527
00528
00529
00530
00531
00532 #define ZERO_LSN(LSN) do { \
00533 (LSN).file = 0; \
00534 (LSN).offset = 0; \
00535 } while (0)
00536 #define IS_ZERO_LSN(LSN) ((LSN).file == 0 && (LSN).offset == 0)
00537
00538 #define IS_INIT_LSN(LSN) ((LSN).file == 1 && (LSN).offset == 0)
00539 #define INIT_LSN(LSN) do { \
00540 (LSN).file = 1; \
00541 (LSN).offset = 0; \
00542 } while (0)
00543
00544 #define MAX_LSN(LSN) do { \
00545 (LSN).file = UINT32_MAX; \
00546 (LSN).offset = UINT32_MAX; \
00547 } while (0)
00548 #define IS_MAX_LSN(LSN) \
00549 ((LSN).file == UINT32_MAX && (LSN).offset == UINT32_MAX)
00550
00551
00552 #define LSN_NOT_LOGGED(LSN) do { \
00553 (LSN).file = 0; \
00554 (LSN).offset = 1; \
00555 } while (0)
00556 #define IS_NOT_LOGGED_LSN(LSN) \
00557 ((LSN).file == 0 && (LSN).offset == 1)
00558
00559
00560
00561
00562 #define DB_NONBLOCK(C) ((C)->txn != NULL && F_ISSET((C)->txn, TXN_NOWAIT))
00563 #define NOWAIT_FLAG(txn) \
00564 ((txn) != NULL && F_ISSET((txn), TXN_NOWAIT) ? DB_LOCK_NOWAIT : 0)
00565 #define IS_SUBTRANSACTION(txn) \
00566 ((txn) != NULL && (txn)->parent != NULL)
00567
00568
00569
00570
00571 #define DB_IV_BYTES 16
00572 #define DB_MAC_KEY 20
00573
00574
00575
00576
00577 #ifdef CONFIG_TEST
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588 #define DB_RPC2ND_MASK 0x00f00000
00589
00590 #define DB_RPC2ND_REVERSEDATA 0x00100000
00591 #define DB_RPC2ND_NOOP 0x00200000
00592 #define DB_RPC2ND_CONCATKEYDATA 0x00300000
00593 #define DB_RPC2ND_CONCATDATAKEY 0x00400000
00594 #define DB_RPC2ND_REVERSECONCAT 0x00500000
00595 #define DB_RPC2ND_TRUNCDATA 0x00600000
00596 #define DB_RPC2ND_CONSTANT 0x00700000
00597 #define DB_RPC2ND_GETZIP 0x00800000
00598 #define DB_RPC2ND_GETNAME 0x00900000
00599 #endif
00600
00601
00602
00603
00604 struct __db_reginfo_t; typedef struct __db_reginfo_t REGINFO;
00605 struct __db_txnhead; typedef struct __db_txnhead DB_TXNHEAD;
00606 struct __db_txnlist; typedef struct __db_txnlist DB_TXNLIST;
00607 struct __vrfy_childinfo;typedef struct __vrfy_childinfo VRFY_CHILDINFO;
00608 struct __vrfy_dbinfo; typedef struct __vrfy_dbinfo VRFY_DBINFO;
00609 struct __vrfy_pageinfo; typedef struct __vrfy_pageinfo VRFY_PAGEINFO;
00610
00611 #if defined(__cplusplus)
00612 }
00613 #endif
00614
00615
00616
00617
00618
00619
00620 #include "dbinc/globals.h"
00621 #include "dbinc/debug.h"
00622 #include "dbinc/region.h"
00623 #include "dbinc_auto/env_ext.h"
00624 #include "dbinc/mutex.h"
00625 #include "dbinc/os.h"
00626 #include "dbinc/rep.h"
00627 #include "dbinc_auto/clib_ext.h"
00628 #include "dbinc_auto/common_ext.h"
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640 #define DBENV_LOGGING(dbenv) \
00641 (LOGGING_ON(dbenv) && !IS_REP_CLIENT(dbenv) && \
00642 (!IS_RECOVERING(dbenv)))
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663 #if defined(DIAGNOSTIC) || defined(DEBUG_ROP) || defined(DEBUG_WOP)
00664 #define DBC_LOGGING(dbc) __dbc_logging(dbc)
00665 #else
00666 #define DBC_LOGGING(dbc) \
00667 ((dbc)->txn != NULL && LOGGING_ON((dbc)->dbp->dbenv) && \
00668 !F_ISSET((dbc), DBC_RECOVER) && !IS_REP_CLIENT((dbc)->dbp->dbenv))
00669 #endif
00670
00671 #endif